// *****************************************************************************
// *****************************************************************************
// Copyright 2013, Cadence Design Systems
//
// This  file  is  part  of  the  Cadence  LEF/DEF  Open   Source
// Distribution,  Product Version 5.8.
//
// Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
//    implied. See the License for the specific language governing
//    permissions and limitations under the License.
//
// For updates, support, or to become part of the LEF/DEF Community,
// check www.openeda.org for details.
//
//  $Author: icftcm $
//  $Revision: #2 $
//  $Date: 2020/12/02 $
//  $State:  $
// *****************************************************************************
// *****************************************************************************

// This file contains code for implementing the defwriter 5.3
// It has all the functions user can call in their callbacks or
// just their writer to write out the correct lef syntax.
//
// Author: Wanda da Rosa
// Date:   Summer, 1998
//
// Revisions: 11/25/2002 - bug fix: submitted by Craig Files
//                         (cfiles@ftc.agilent.com)
//                         Changed all (!name && !*name) to
//                         (!name || !*name)

#include "defwWriter.hpp"

#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>

#include "defiUtil.hpp"

BEGIN_DEF_PARSER_NAMESPACE

// States of the writer.
#define DEFW_UNINIT 0
#define DEFW_INIT 1
#define DEFW_VERSION 2
#define DEFW_CASESENSITIVE 3
#define DEFW_DIVIDER 4
#define DEFW_BUSBIT 5
#define DEFW_DESIGN 6
#define DEFW_TECHNOLOGY 7
#define DEFW_ARRAY 8
#define DEFW_FLOORPLAN 9
#define DEFW_UNITS 10
#define DEFW_HISTORY 11
#define DEFW_PROP_START 12
#define DEFW_PROP 13
#define DEFW_PROP_END 14
#define DEFW_DIE_AREA 15
#define DEFW_ROW 16
#define DEFW_TRACKS 17
#define DEFW_GCELL_GRID 18
#define DEFW_DEFAULTCAP_START 19
#define DEFW_DEFAULTCAP 20
#define DEFW_DEFAULTCAP_END 21
#define DEFW_CANPLACE 22
#define DEFW_CANNOTOCCUPY 23
#define DEFW_VIA_START 24
#define DEFW_VIA 25
#define DEFW_VIAVIARULE 26
#define DEFW_VIAONE_END 27
#define DEFW_VIA_END 28
#define DEFW_REGION_START 29
#define DEFW_REGION 30
#define DEFW_REGION_END 31
#define DEFW_COMPONENT_MASKSHIFTLAYERS 32
#define DEFW_COMPONENT_START 33
#define DEFW_COMPONENT 34
#define DEFW_COMPONENT_END 35
#define DEFW_PIN_START 36
#define DEFW_PIN 37
#define DEFW_PIN_PORT 38
#define DEFW_PIN_END 39
#define DEFW_PINPROP_START 40
#define DEFW_PINPROP 41
#define DEFW_PINPROP_END 42
#define DEFW_BLOCKAGE_START 43
#define DEFW_BLOCKAGE_LAYER 44
#define DEFW_BLOCKAGE_PLACE 45
#define DEFW_BLOCKAGE_RECT 46
#define DEFW_BLOCKAGE_POLYGON 47
#define DEFW_BLOCKAGE_END 48
#define DEFW_SNET_START 49
#define DEFW_SNET 50
#define DEFW_SNET_OPTIONS 51
#define DEFW_SNET_ENDNET 52
#define DEFW_SNET_END 53
#define DEFW_PATH_START 54
#define DEFW_PATH 55
#define DEFW_SHIELD 56
#define DEFW_NET_START 57
#define DEFW_NET 58
#define DEFW_NET_OPTIONS 59
#define DEFW_NET_ENDNET 60
#define DEFW_NET_END 61
#define DEFW_SUBNET 62
#define DEFW_NOSHIELD 63
#define DEFW_IOTIMING_START 64
#define DEFW_IOTIMING 65
#define DEFW_IOTIMING_END 66
#define DEFW_SCANCHAIN_START 67
#define DEFW_SCANCHAIN 68
#define DEFW_SCAN_FLOATING 69
#define DEFW_SCAN_ORDERED 70
#define DEFW_SCANCHAIN_END 71
#define DEFW_FPC_START 72
#define DEFW_FPC 73
#define DEFW_FPC_OPER 74
#define DEFW_FPC_OPER_SUM 75
#define DEFW_FPC_END 76
#define DEFW_GROUP_START 77
#define DEFW_GROUP 78
#define DEFW_GROUP_END 79
#define DEFW_SLOT_START 80
#define DEFW_SLOT_LAYER 81
#define DEFW_SLOT_RECT 82
#define DEFW_SLOT_END 83
#define DEFW_FILL_START 84
#define DEFW_FILL_LAYER 85
#define DEFW_FILL_VIA 86
#define DEFW_FILL_OPC 87
#define DEFW_FILL_RECT 88
#define DEFW_FILL_END 89
#define DEFW_NDR_START 90
#define DEFW_NDR 91
#define DEFW_NDR_END 92
#define DEFW_STYLES_START 93
#define DEFW_STYLES 94
#define DEFW_STYLES_END 95
#define DEFW_BEGINEXT_START 96
#define DEFW_BEGINEXT 97
#define DEFW_BEGINEXT_END 98
#define DEFW_FILL_LAYERMASK 99
#define DEFW_FILL_VIAMASK 100
#define DEFW_BLOCKAGE_MASK 101

#define DEFW_END 102

#define DEFW_DONE 999

#define MAXSYN 103

// *****************************************************************************
//        Global Variables
// *****************************************************************************
FILE* defwFile = nullptr;     // File to write to.
int defwLines = 0;            // number of lines written
int defwState = DEFW_UNINIT;  // Current state of writer
int defwFunc = DEFW_UNINIT;   // Current function of writer
int defwDidNets = 0;          // required section
int defwDidComponents = 0;    // required section
int defwDidInit = 0;          // required section
int defwCounter = 0;          // number of nets, components in section
int defwLineItemCounter = 0;  // number of items on current line
int defwFPC = 0;          // Current number of items in constraints/operand/sum
int defwHasInit = 0;      // for defwInit has called
int defwHasInitCbk = 0;   // for defwInitCbk has called
int defwSpNetShield = 0;  // for special net shieldNetName
static double defVersionNum = 5.7;  // default to 5.7
static int defwObsoleteNum = -1;    // keep track the obsolete syntax for error
static int defwViaHasVal = 0;       // keep track only ViaRule|Pattern
static int defwBlockageHasSD = 0;   // keep track only Spacing|Designrulewidth
static int defwBlockageHasSF = 0;   // keep track only SLOTS|FILLS
static int defwBlockageHasSP = 0;   // keep track only SOFT|PARTIAL

char defwStateStr[MAXSYN][80] = {
    "UNINITIALIZE",         //  0
    "INITIALIZE",           //  1
    "VERSION",              //  2
    "CASESENSITIVE",        //  3
    "BUSBIT",               //  4
    "DIVIDER",              //  5
    "DESIGN",               //  6
    "TECHNOLOGY",           //  7
    "ARRAY",                //  8
    "FLOORPLAN",            //  9
    "UNITS",                // 10
    "HISTORY",              // 11
    "PROPERTYDEFINITIONS",  // 12
    "PROPERTYDEFINITIONS",  // 13
    "PROPERTYDEFINITIONS",  // 14
    "DIEAREA",              // 15
    "ROW",                  // 16
    "TRACKS",               // 17
    "GCELLGRID",            // 18
    "DEFAULTCAP",           // 19
    "DEFAULTCAP",           // 20
    "DEFAULTCAP",           // 21
    "CANPLACE",             // 22
    "CANNOTOCCUPY",         // 23
    "VIA",                  // 24
    "VIA",                  // 25
    "VIA",                  // 26
    "VIA",                  // 27
    "VIA",                  // 28
    "REGION",               // 29
    "REGION",               // 30
    "REGION",               // 31
    "COMPONENT",            // 32
    "COMPONENT",            // 33
    "COMPONENT",            // 34
    "COMPONENT",            // 35
    "PIN",                  // 36
    "PIN",                  // 37
    "PIN",                  // 38
    "PIN",                  // 39
    "PINPROPERTY",          // 40
    "PINPROPERTY",          // 41
    "PINPROPERTY",          // 42
    "SNET",                 // 43
    "SNET",                 // 44
    "SNET",                 // 45
    "SNET",                 // 46
    "SNET",                 // 47
    "PATH",                 // 48
    "PATH",                 // 49
    "SHIELD",               // 50
    "NET",                  // 51
    "NET",                  // 52
    "NET",                  // 53
    "NET",                  // 54
    "NET",                  // 55
    "SUBNET",               // 56
    "NOSHIELD",             // 57
    "IOTIMING",             // 58
    "IOTIMING",             // 59
    "IOTIMING",             // 60
    "SCANCHAIN",            // 61
    "SCANCHAIN",            // 62
    "SCAN FLOATING",        // 63
    "SCAN ORDERED",         // 64
    "SCANCHAIN",            // 65
    "CONSTRAINTS",          // 66
    "CONSTRAINTS",          // 67
    "CONSTRAINTS",          // 68
    "CONSTRAINTS",          // 69
    "CONSTRAINTS",          // 70
    "GROUP",                // 71
    "GROUP",                // 71
    "GROUP",                // 72
    "BLOCKAGE",             // 73
    "BLOCKAGE LAYER",       // 74
    "BLOCKAGE PLACEMENT",   // 75
    "BLOCKAGE RECT",        // 76
    "BLOCKAGE POLYGON",     // 77
    "BLOCKAGE",             // 78
    "SLOT",                 // 79
    "SLOT",                 // 80
    "SLOT",                 // 81
    "SLOT",                 // 82
    "FILL",                 // 83
    "FILL",                 // 84
    "FILL",                 // 85
    "FILL",                 // 86
    "FILL",                 // 87
    "FILL",                 // 88
    "NDR",                  // 89
    "NDR",                  // 90
    "NDR",                  // 91
    "STYLES",               // 92
    "STYLES",               // 93
    "STYLES",               // 94
    "BEGINEXT",             // 95
    "BEGINEXT",             // 96
    "BEGINEXT",             // 97
    "DESIGN END",           // 98
    "FILL_LAYERMASK",       // 99
    "FILL_VIAMASK",         // 100
    "BLOCKAGE_MASK"         // 101

};

static int printPointsNum = 0;
static void printPoints(FILE* file,
                        double x,
                        double y,
                        const char* prefix,
                        const char* suffix)
{
  static double x_old = 0;
  static double y_old = 0;

  fprintf(file, "%s", prefix);

  if (printPointsNum++ == 0) {
    fprintf(file, "( %.11g %.11g )", x, y);
  } else if (x_old == x) {
    if (y_old == y) {
      fprintf(file, "( * * )");
    } else {
      fprintf(file, "( * %.11g )", y);
    }
  } else if (y_old == y) {
    fprintf(file, "( %.11g * )", x);
  } else {
    fprintf(file, "( %.11g %.11g )", x, y);
  }

  fprintf(file, "%s", suffix);

  x_old = x;
  y_old = y;
}

int defwNewLine()
{
  if (!defwFile) {
    return DEFW_BAD_ORDER;
  }
  fprintf(defwFile, "\n");
  return DEFW_OK;
}

// this function is required to be called first to initialize the required
// sections.
// Either this function or defwInitCbk can be called, cannot be both
int defwInit(FILE* f,
             int vers1,
             int vers2,
             const char* caseSensitive,
             const char* dividerChar,
             const char* busBitChars,
             const char* designName,
             const char* technology,  // optional
             const char* array,       // optional
             const char* floorplan,   // optional
             double units             // optional  (set to -1 to ignore)
)
{
  // if (defwFile) return DEFW_BAD_ORDER;
  defwFile = f;
  if (defwHasInitCbk == 1) {  // defwInitCbk has already called, issue an error
    fprintf(stderr,
            "ERROR (DEFWRIT-9000): The DEF writer has detected that the "
            "function defwInitCbk has already been called and you are trying "
            "to call defwInit.\nOnly defwInitCbk or defwInit can be called but "
            "not both.\nUpdate your program and then try again.\n");
    fprintf(stderr, "Writer Exit.\n");
    exit(DEFW_BAD_ORDER);
  }

  defwState = DEFW_UNINIT;  // Current state of writer
  defwFunc = DEFW_UNINIT;   // Current function of writer
  defwDidNets = 0;          // required section
  defwDidComponents = 0;    // required section
  defwDidInit = 0;          // required section

  if (vers1) {  // optional in 5.6 on
    fprintf(defwFile, "VERSION %d.%d ;\n", vers1, vers2);
    defwLines++;
  }

  if ((vers1 == 5) && (vers2 < 6)) {  // For version before 5.6
    if (caseSensitive == nullptr || *caseSensitive == 0) {
      return DEFW_BAD_DATA;
    }
    fprintf(defwFile, "NAMESCASESENSITIVE %s ;\n", caseSensitive);
  }

  if (dividerChar) {  // optional in 5.6 on
    fprintf(defwFile, "DIVIDERCHAR \"%s\" ;\n", dividerChar);
    defwLines++;
  }

  if (busBitChars) {  // optional in 5.6 on
    fprintf(defwFile, "BUSBITCHARS \"%s\" ;\n", busBitChars);
    defwLines++;
  }

  if (designName == nullptr || *designName == 0) {
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "DESIGN %s ;\n", designName);
  defwLines++;

  if (technology) {
    fprintf(defwFile, "TECHNOLOGY %s ;\n", technology);
    defwLines++;
  }

  if (array) {
    fprintf(defwFile, "ARRAY %s ;\n", array);
    defwLines++;
  }

  if (floorplan) {
    fprintf(defwFile, "FLOORPLAN %s ;\n", floorplan);
    defwLines++;
  }

  if (units != -1.0) {
    int unitsVal = (int) units;
    switch (unitsVal) {
      case 100:
      case 200:
      case 1000:
      case 2000:
      case 4000:
      case 8000:
      case 10000:
      case 16000:
      case 20000:
        fprintf(defwFile, "UNITS DISTANCE MICRONS %ld ;\n", std::lround(units));
        defwLines++;
        break;
      default:
        return DEFW_BAD_DATA;
    }
  }

  defwDidInit = 1;
  defwState = DEFW_DESIGN;
  defwHasInit = 1;
  return DEFW_OK;
}

// this function is required to be called first to initialize the variables
// Either this function or defwInit can be called, cannot be both
int defwInitCbk(FILE* f)
{
  defwFile = f;
  if (defwHasInit == 1) {  // defwInit has already called, issue an error
    fprintf(stderr,
            "ERROR (DEFWRIT-9001): The DEF writer has detected that the "
            "function defwInit has already been called and you are trying to "
            "call defwInitCbk.\nOnly defwInitCbk or defwInit can be called but "
            "not both.\nUpdate your program and then try again.\n");
    fprintf(stderr, "Writer Exit.\n");
    exit(DEFW_BAD_ORDER);
  }

  defwState = DEFW_UNINIT;  // Current state of writer
  defwFunc = DEFW_UNINIT;   // Current function of writer
  defwDidNets = 0;          // required section
  defwDidComponents = 0;    // required section
  defwDidInit = 0;          // required section

  defwDidInit = 1;
  defwState = DEFW_INIT;
  defwHasInitCbk = 1;
  return DEFW_OK;
}

int defwVersion(int vers1, int vers2)
{
  defwFunc = DEFW_VERSION;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState != DEFW_INIT) {  // version follows init
    return DEFW_BAD_ORDER;
  }
  fprintf(defwFile, "VERSION %d.%d ;\n", vers1, vers2);
  if (vers2 >= 10) {
    defVersionNum = vers1 + (vers2 / 100.0);
  } else {
    defVersionNum = vers1 + (vers2 / 10.0);
  }
  defwLines++;

  defwState = DEFW_VERSION;
  return DEFW_OK;
}

int defwCaseSensitive(const char* caseSensitive)
{
  defwObsoleteNum = DEFW_CASESENSITIVE;
  defwFunc = DEFW_CASESENSITIVE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum >= 5.6) {
    return DEFW_OBSOLETE;
  }
  // Check for repeated casesensitive
  if (defwState == DEFW_CASESENSITIVE) {
    return DEFW_BAD_ORDER;
  }
  if (strcmp(caseSensitive, "ON") && strcmp(caseSensitive, "OFF")) {
    return DEFW_BAD_DATA;  // has to be either ON or OFF
  }
  fprintf(defwFile, "NAMESCASESENSITIVE %s ;\n", caseSensitive);
  defwLines++;

  defwState = DEFW_CASESENSITIVE;
  return DEFW_OK;
}

int defwBusBitChars(const char* busBitChars)
{
  defwFunc = DEFW_BUSBIT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  // Check for repeated casesensitive
  if (defwState == DEFW_BUSBIT) {
    return DEFW_BAD_ORDER;
  }
  if (busBitChars && busBitChars != nullptr && *busBitChars != 0) {
    fprintf(defwFile, "BUSBITCHARS \"%s\" ;\n", busBitChars);
    defwLines++;
  }

  defwState = DEFW_BUSBIT;
  return DEFW_OK;
}

int defwDividerChar(const char* dividerChar)
{
  defwFunc = DEFW_DIVIDER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  // Check for repeated busbit
  if (defwState == DEFW_DIVIDER) {
    return DEFW_BAD_ORDER;
  }
  if (dividerChar && dividerChar != nullptr && *dividerChar != 0) {
    fprintf(defwFile, "DIVIDERCHAR \"%s\" ;\n", dividerChar);
    defwLines++;
  }

  defwState = DEFW_DIVIDER;
  return DEFW_OK;
}

int defwDesignName(const char* name)
{
  defwFunc = DEFW_DESIGN;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  // Check for repeated design
  if (defwState == DEFW_DESIGN) {
    return DEFW_BAD_ORDER;
  }
  if (name && name != nullptr && *name != 0) {
    fprintf(defwFile, "DESIGN %s ;\n", name);
    defwLines++;
  }

  defwState = DEFW_DESIGN;
  return DEFW_OK;
}

int defwTechnology(const char* technology)
{
  defwFunc = DEFW_TECHNOLOGY;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (technology && technology != nullptr && *technology != 0) {
    fprintf(defwFile, "TECHNOLOGY %s ;\n", technology);
    defwLines++;
  }

  defwState = DEFW_TECHNOLOGY;
  return DEFW_OK;
}

int defwArray(const char* array)
{
  defwFunc = DEFW_ARRAY;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState == DEFW_ARRAY) {
    return DEFW_BAD_ORDER;  // check for repeated array
  }
  if (array && array != nullptr && *array != 0) {
    fprintf(defwFile, "ARRAY %s ;\n", array);
    defwLines++;
  }

  defwState = DEFW_ARRAY;
  return DEFW_OK;
}

int defwFloorplan(const char* floorplan)
{
  defwFunc = DEFW_FLOORPLAN;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState == DEFW_FLOORPLAN) {
    return DEFW_BAD_ORDER;  // Check for repeated floorplan
  }
  if (floorplan && floorplan != nullptr && *floorplan != 0) {
    fprintf(defwFile, "FLOORPLAN %s ;\n", floorplan);
    defwLines++;
  }

  defwState = DEFW_FLOORPLAN;
  return DEFW_OK;
}

int defwUnits(int units)
{
  defwFunc = DEFW_UNITS;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState == DEFW_UNITS) {
    return DEFW_BAD_ORDER;  // Check for repeated units
  }
  if (units != 0) {
    switch (units) {
      case 100:
      case 200:
      case 400:
      case 800:
      case 1000:
      case 2000:
      case 4000:
      case 8000:
      case 10000:
      case 20000:
        fprintf(defwFile, "UNITS DISTANCE MICRONS %d ;\n", units);
        defwLines++;
        break;
      default:
        return DEFW_BAD_DATA;
    }
  }

  defwState = DEFW_UNITS;
  return DEFW_OK;
}

int defwHistory(const char* string)
{
  char* c;
  defwFunc = DEFW_HISTORY;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (string == nullptr || *string == 0) {
    return DEFW_BAD_DATA;
  }

  for (c = (char*) string; *c; c++) {
    if (*c == '\n') {
      defwLines++;
    }
  }

  fprintf(defwFile, "HISTORY %s ;\n", string);
  defwLines++;

  defwState = DEFW_HISTORY;
  return DEFW_OK;
}

int defwStartPropDef()
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if ((defwState >= DEFW_PROP_START) && (defwState <= DEFW_PROP_END)) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "PROPERTYDEFINITIONS\n");
  defwLines++;

  defwState = DEFW_PROP_START;
  return DEFW_OK;
}

int defwIsPropObjType(const char* objType)
{
  if (strcmp(objType, "DESIGN") && strcmp(objType, "COMPONENT")
      && strcmp(objType, "NET") && strcmp(objType, "SPECIALNET")
      && strcmp(objType, "GROUP") && strcmp(objType, "ROW")
      && strcmp(objType, "COMPONENTPIN") && strcmp(objType, "REGION")
      && strcmp(objType, "NONDEFAULTRULE")) {
    return 0;
  }
  return 1;
}

int defwIntPropDef(const char* objType,
                   const char* propName,
                   double leftRange,
                   double rightRange,  // optional
                   int propValue       // optional
)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PROP_START && defwState != DEFW_PROP) {
    return DEFW_BAD_ORDER;
  }
  if ((!objType || !*objType) || (!propName || !*propName)) {  // require
    return DEFW_BAD_DATA;
  }

  if (!defwIsPropObjType(objType)) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "   %s %s INTEGER ", objType, propName);
  if (leftRange || rightRange) {
    fprintf(defwFile, "RANGE %.11g %.11g ", leftRange, rightRange);
  }

  if (propValue) {
    fprintf(defwFile, "%d ", propValue);
  }

  fprintf(defwFile, ";\n");

  defwLines++;
  defwState = DEFW_PROP;
  return DEFW_OK;
}

int defwRealPropDef(const char* objType,
                    const char* propName,
                    double leftRange,
                    double rightRange,  // optional
                    double propValue    // optional
)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PROP_START && defwState != DEFW_PROP) {
    return DEFW_BAD_ORDER;
  }
  if ((!objType || !*objType) || (!propName || !*propName)) {  // require
    return DEFW_BAD_DATA;
  }

  if (!defwIsPropObjType(objType)) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "   %s %s REAL ", objType, propName);
  if (leftRange || rightRange) {
    fprintf(defwFile, "RANGE %.11g %.11g ", leftRange, rightRange);
  }

  if (propValue) {
    fprintf(defwFile, "%.11g ", propValue);
  }

  fprintf(defwFile, ";\n");

  defwLines++;
  defwState = DEFW_PROP;
  return DEFW_OK;
}

int defwStringPropDef(const char* objType,
                      const char* propName,
                      double leftRange,
                      double rightRange,     // optional
                      const char* propValue  // optional
)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PROP_START && defwState != DEFW_PROP) {
    return DEFW_BAD_ORDER;
  }
  if ((!objType || !*objType) || (!propName || !*propName)) {
    return DEFW_BAD_DATA;
  }

  if (!defwIsPropObjType(objType)) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "   %s %s STRING ", objType, propName);
  if (leftRange || rightRange) {
    fprintf(defwFile, "RANGE %.11g %.11g ", leftRange, rightRange);
  }

  if (propValue) {
    fprintf(defwFile, "\"%s\" ", propValue);  // string, set quotes
  }

  fprintf(defwFile, ";\n");

  defwLines++;
  defwState = DEFW_PROP;
  return DEFW_OK;
}

int defwEndPropDef()
{
  defwFunc = DEFW_PROP_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PROP_START && defwState != DEFW_PROP) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "END PROPERTYDEFINITIONS\n\n");
  defwLines++;

  defwState = DEFW_PROP_END;
  return DEFW_OK;
}

int defwIsPropState()
{
  if ((defwState != DEFW_ROW) && (defwState != DEFW_REGION)
      && (defwState != DEFW_COMPONENT) && (defwState != DEFW_PIN)
      && (defwState != DEFW_SNET) && (defwState != DEFW_NET)
      && (defwState != DEFW_GROUP) && (defwState != DEFW_PINPROP)
      && (defwState != DEFW_SNET_OPTIONS) && (defwState != DEFW_NET_OPTIONS)
      && (defwState != DEFW_NDR) && (defwState != DEFW_BEGINEXT)) {
    return 0;
  }
  return 1;
}

int defwStringProperty(const char* propName, const char* propValue)
{
  if (!defwIsPropState()) {
    return DEFW_BAD_ORDER;
  }

  // new line for the defwRow of the previous line
  // do not end with newline, may have more than on properties
  fprintf(defwFile, "\n      + PROPERTY %s \"%s\" ", propName, propValue);
  defwLines++;
  return DEFW_OK;
}

int defwRealProperty(const char* propName, double propValue)
{
  if (!defwIsPropState()) {
    return DEFW_BAD_ORDER;
  }

  // new line for the defwRow of the previous line
  // do not end with newline, may have more than on properties
  fprintf(defwFile, "\n      + PROPERTY %s %.11g ", propName, propValue);
  defwLines++;
  return DEFW_OK;
}

int defwIntProperty(const char* propName, int propValue)
{
  if (!defwIsPropState()) {
    return DEFW_BAD_ORDER;
  }

  // new line for the defwRow of the previous line
  // do not end with newline, may have more than on properties
  fprintf(defwFile, "\n      + PROPERTY %s %d ", propName, propValue);
  defwLines++;
  return DEFW_OK;
}

int defwDieArea(int xl, int yl, int xh, int yh)
{
  defwFunc = DEFW_DIE_AREA;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState == DEFW_DIE_AREA) {
    return DEFW_BAD_ORDER;
  }
  if (xl > xh || yl > yh) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "DIEAREA ( %d %d ) ( %d %d ) ;\n", xl, yl, xh, yh);
  defwLines++;

  defwState = DEFW_DIE_AREA;
  return DEFW_OK;
}

int defwDieAreaList(int num_points, int* xl, int* yl)
{
  int i;

  defwFunc = DEFW_DIE_AREA;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState == DEFW_DIE_AREA) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }
  if (num_points < 4) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "DIEAREA ");
  for (i = 0; i < num_points; i++) {
    if (i == 0) {
      fprintf(defwFile, "( %d %d ) ", *xl++, *yl++);
    } else {
      if ((i % 5) == 0) {
        fprintf(defwFile, "\n        ( %d %d ) ", *xl++, *yl++);
        defwLines++;
      } else {
        fprintf(defwFile, "( %d %d ) ", *xl++, *yl++);
      }
    }
  }
  fprintf(defwFile, ";\n");
  defwLines++;

  defwState = DEFW_DIE_AREA;
  return DEFW_OK;
}

char* defwAddr(const char* x)
{
  return (char*) x;
}

char* defwOrient(int num)
{
  switch (num) {
    case 0:
      return defwAddr("N");
    case 1:
      return defwAddr("W");
    case 2:
      return defwAddr("S");
    case 3:
      return defwAddr("E");
    case 4:
      return defwAddr("FN");
    case 5:
      return defwAddr("FW");
    case 6:
      return defwAddr("FS");
    case 7:
      return defwAddr("FE");
  };
  return defwAddr("BOGUS ");
}

int defwRow(const char* rowName,
            const char* rowType,
            int x_orig,
            int y_orig,
            int orient,
            int do_count,
            int do_increment,
            int do_x,
            int do_y)
{
  defwFunc = DEFW_ROW;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n");  // add the ; and newline for the previous row.
  }

  // required
  if ((rowName == nullptr) || (*rowName == 0) || (rowType == nullptr)
      || (*rowType == 0)) {
    return DEFW_BAD_DATA;
  }

  // do not have ; because the row may have properties
  // do not end with newline, if there is no property, ; need to be concat.
  fprintf(defwFile,
          "ROW %s %s %d %d %s ",
          rowName,
          rowType,
          x_orig,
          y_orig,
          defwOrient(orient));
  if ((do_count != 0) || (do_increment != 0)) {
    fprintf(defwFile, "DO %d BY %d ", do_count, do_increment);
    if ((do_x != 0) || (do_y != 0)) {
      fprintf(defwFile, "STEP %d %d ", do_x, do_y);
    }
  }
  defwLines++;

  defwState = DEFW_ROW;
  return DEFW_OK;
}

int defwRowStr(const char* rowName,
               const char* rowType,
               int x_orig,
               int y_orig,
               const char* orient,
               int do_count,
               int do_increment,
               int do_x,
               int do_y)
{
  defwFunc = DEFW_ROW;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n");  // add the ; and newline for the previous row.
  }

  if ((!rowName || !*rowName) || (!rowType || !*rowType)) {  // required
    return DEFW_BAD_DATA;
  }

  // do not have ; because the row may have properties
  // do not end with newline, if there is no property, ; need to be concat.
  fprintf(defwFile,
          "ROW %s %s %d %d %s ",
          rowName,
          rowType,
          x_orig,
          y_orig,
          orient);
  if ((do_count != 0) || (do_increment != 0)) {
    fprintf(defwFile, "DO %d BY %d ", do_count, do_increment);
    if ((do_x != 0) || (do_y != 0)) {
      fprintf(defwFile, "STEP %d %d ", do_x, do_y);
    }
  }
  defwLines++;

  defwState = DEFW_ROW;
  return DEFW_OK;
}

int defwTracks(const char* master,
               int do_start,
               int do_cnt,
               int do_step,
               int num_layers,
               const char** layers,
               int mask,
               int sameMask)
{
  int i;

  defwFunc = DEFW_TRACKS;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row
  }

  if (!master || !*master) {  // required
    return DEFW_BAD_DATA;
  }
  if (strcmp(master, "X") && strcmp(master, "Y")) {
    return DEFW_BAD_DATA;
  }

  if (mask) {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    if (sameMask) {
      fprintf(defwFile,
              "TRACKS %s %d DO %d STEP %d MASK %d SAMEMASK LAYER",
              master,
              do_start,
              do_cnt,
              do_step,
              mask);
    } else {
      fprintf(defwFile,
              "TRACKS %s %d DO %d STEP %d MASK %d LAYER",
              master,
              do_start,
              do_cnt,
              do_step,
              mask);
    }
  } else {
    fprintf(defwFile,
            "TRACKS %s %d DO %d STEP %d LAYER",
            master,
            do_start,
            do_cnt,
            do_step);
  }

  for (i = 0; i < num_layers; i++) {
    fprintf(defwFile, " %s", layers[i]);
  }
  fprintf(defwFile, " ;\n");
  defwLines++;

  defwState = DEFW_TRACKS;
  return DEFW_OK;
}

int defwGcellGrid(const char* master, int do_start, int do_cnt, int do_step)
{
  defwFunc = DEFW_GCELL_GRID;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row.
  }

  if (!master || !*master) {  // required
    return DEFW_BAD_DATA;
  }
  if (strcmp(master, "X") && strcmp(master, "Y")) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile,
          "GCELLGRID %s %d DO %d STEP %d ;\n",
          master,
          do_start,
          do_cnt,
          do_step);
  defwLines++;

  defwState = DEFW_GCELL_GRID;
  return DEFW_OK;
}

int defwStartDefaultCap(int count)
{
  defwObsoleteNum = DEFW_DEFAULTCAP_START;
  defwFunc = DEFW_DEFAULTCAP_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if ((defwState >= DEFW_DEFAULTCAP_START)
      && (defwState <= DEFW_DEFAULTCAP_END)) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum >= 5.4) {
    return DEFW_OBSOLETE;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row.
  }

  fprintf(defwFile, "DEFAULTCAP %d\n", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_DEFAULTCAP_START;
  return DEFW_OK;
}

int defwDefaultCap(int pins, double cap)
{
  defwFunc = DEFW_DEFAULTCAP;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_DEFAULTCAP_START && defwState != DEFW_DEFAULTCAP) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "   MINPINS %d WIRECAP %f ;\n", pins, cap);
  defwLines++;
  defwCounter--;

  defwState = DEFW_DEFAULTCAP;
  return DEFW_OK;
}

int defwEndDefaultCap()
{
  defwFunc = DEFW_DEFAULTCAP_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_DEFAULTCAP_START && defwState != DEFW_DEFAULTCAP) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, "END DEFAULTCAP\n\n");
  defwLines++;

  defwState = DEFW_DEFAULTCAP_END;
  return DEFW_OK;
}

int defwCanPlace(const char* master,
                 int xOrig,
                 int yOrig,
                 int orient,
                 int doCnt,
                 int doInc,
                 int xStep,
                 int yStep)
{
  defwFunc = DEFW_CANPLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row.
  }

  if ((master == nullptr) || (*master == 0)) {  // required
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile,
          "CANPLACE %s %d %d %s DO %d BY %d STEP %d %d ;\n",
          master,
          xOrig,
          yOrig,
          defwOrient(orient),
          doCnt,
          doInc,
          xStep,
          yStep);
  defwLines++;

  defwState = DEFW_CANPLACE;
  return DEFW_OK;
}

int defwCanPlaceStr(const char* master,
                    int xOrig,
                    int yOrig,
                    const char* orient,
                    int doCnt,
                    int doInc,
                    int xStep,
                    int yStep)
{
  defwFunc = DEFW_CANPLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row.
  }

  if (!master || !*master) {  // required
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile,
          "CANPLACE %s %d %d %s DO %d BY %d STEP %d %d ;\n",
          master,
          xOrig,
          yOrig,
          orient,
          doCnt,
          doInc,
          xStep,
          yStep);
  defwLines++;

  defwState = DEFW_CANPLACE;
  return DEFW_OK;
}

int defwCannotOccupy(const char* master,
                     int xOrig,
                     int yOrig,
                     int orient,
                     int doCnt,
                     int doInc,
                     int xStep,
                     int yStep)
{
  defwFunc = DEFW_CANNOTOCCUPY;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }

  if ((master == nullptr) || (*master == 0)) {  // required
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile,
          "CANNOTOCCUPY %s %d %d %s DO %d BY %d STEP %d %d ;\n",
          master,
          xOrig,
          yOrig,
          defwOrient(orient),
          doCnt,
          doInc,
          xStep,
          yStep);
  defwLines++;

  defwState = DEFW_CANNOTOCCUPY;
  return DEFW_OK;
}

int defwCannotOccupyStr(const char* master,
                        int xOrig,
                        int yOrig,
                        const char* orient,
                        int doCnt,
                        int doInc,
                        int xStep,
                        int yStep)
{
  defwFunc = DEFW_CANNOTOCCUPY;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }

  if (!master || !*master) {  // required
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile,
          "CANNOTOCCUPY %s %d %d %s DO %d BY %d STEP %d %d ;\n",
          master,
          xOrig,
          yOrig,
          orient,
          doCnt,
          doInc,
          xStep,
          yStep);
  defwLines++;

  defwState = DEFW_CANNOTOCCUPY;
  return DEFW_OK;
}

int defwStartVias(int count)
{
  defwFunc = DEFW_VIA_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if ((defwState >= DEFW_VIA_START) && (defwState <= DEFW_VIA_END)) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row.
  }

  fprintf(defwFile, "VIAS %d ;\n", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_VIA_START;
  return DEFW_OK;
}

int defwViaName(const char* name)
{
  defwFunc = DEFW_VIA;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIA_START && defwState != DEFW_VIAONE_END) {
    return DEFW_BAD_ORDER;
  }
  defwCounter--;

  if (!name || !*name) {  // required
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "   - %s", name);

  defwState = DEFW_VIA;
  defwViaHasVal = 0;
  return DEFW_OK;
}

int defwViaPattern(const char* pattern)
{
  defwFunc = DEFW_VIA;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIA) {
    return DEFW_BAD_ORDER;  // after defwViaName
  }

  if (defwViaHasVal) {
    return DEFW_ALREADY_DEFINED;  // either PatternName or
  }
  // ViaRule has defined
  if (!pattern || !*pattern) {  // required
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, " + PATTERNNAME %s", pattern);

  defwState = DEFW_VIA;
  defwViaHasVal = 1;
  return DEFW_OK;
}

int defwViaRect(const char* layerNames,
                int xl,
                int yl,
                int xh,
                int yh,
                int mask)
{
  defwFunc = DEFW_VIA;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIA) {
    return DEFW_BAD_ORDER;
  }

  if (!layerNames || !*layerNames) {  // required
    return DEFW_BAD_DATA;
  }
  if (!mask) {
    fprintf(defwFile,
            "\n      + RECT %s ( %d %d ) ( %d %d )",
            layerNames,
            xl,
            yl,
            xh,
            yh);
  } else {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    fprintf(defwFile,
            "\n      + RECT %s + MASK %d ( %d %d ) ( %d %d )",
            layerNames,
            mask,
            xl,
            yl,
            xh,
            yh);
  }
  defwLines++;

  defwState = DEFW_VIA;
  return DEFW_OK;
}

int defwViaPolygon(const char* layerName,
                   int num_polys,
                   double* xl,
                   double* yl,
                   int mask)
{
  int i;

  defwFunc = DEFW_VIA;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIA) {
    return DEFW_BAD_ORDER;
  }

  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }

  if (!mask) {
    fprintf(defwFile, "\n      + POLYGON %s ", layerName);
  } else {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    fprintf(defwFile, "\n      + POLYGON %s + MASK %d ", layerName, mask);
  }

  printPointsNum = 0;
  for (i = 0; i < num_polys; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      printPoints(defwFile, *xl++, *yl++, "", " ");
    } else {
      printPoints(defwFile, *xl++, *yl++, "\n                ", " ");
      defwLines++;
    }
  }
  defwLines++;
  return DEFW_OK;
}

int defwViaViarule(const char* viaRuleName,
                   double xCutSize,
                   double yCutSize,
                   const char* botMetalLayer,
                   const char* cutLayer,
                   const char* topMetalLayer,
                   double xCutSpacing,
                   double yCutSpacing,
                   double xBotEnc,
                   double yBotEnc,
                   double xTopEnc,
                   double yTopEnc)
{
  defwFunc = DEFW_VIA;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIA) {
    return DEFW_BAD_ORDER;
  }
  if (defwViaHasVal) {
    return DEFW_ALREADY_DEFINED;  // either PatternName or
  }
  // ViaRule has defined
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, " + VIARULE %s\n", viaRuleName);
  fprintf(defwFile, "      + CUTSIZE %.11g %.11g\n", xCutSize, yCutSize);
  fprintf(defwFile,
          "      + LAYERS %s %s %s\n",
          botMetalLayer,
          cutLayer,
          topMetalLayer);
  fprintf(
      defwFile, "      + CUTSPACING %.11g %.11g\n", xCutSpacing, yCutSpacing);
  fprintf(defwFile,
          "      + ENCLOSURE %.11g %.11g %.11g %.11g",
          xBotEnc,
          yBotEnc,
          xTopEnc,
          yTopEnc);
  defwLines += 5;
  defwState = DEFW_VIAVIARULE;
  defwViaHasVal = 1;
  return DEFW_OK;
}

int defwViaViaruleRowCol(int numCutRows, int numCutCols)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIAVIARULE) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + ROWCOL %d %d", numCutRows, numCutCols);
  defwLines++;
  return DEFW_OK;
}

int defwViaViaruleOrigin(int xOffset, int yOffset)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIAVIARULE) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + ORIGIN %d %d", xOffset, yOffset);
  defwLines++;
  return DEFW_OK;
}

int defwViaViaruleOffset(int xBotOffset,
                         int yBotOffset,
                         int xTopOffset,
                         int yTopOffset)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIAVIARULE) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile,
          "\n      + OFFSET %d %d %d %d",
          xBotOffset,
          yBotOffset,
          xTopOffset,
          yTopOffset);
  defwLines++;
  return DEFW_OK;
}

int defwViaViarulePattern(const char* cutPattern)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIAVIARULE) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + PATTERN %s", cutPattern);
  defwLines++;
  return DEFW_OK;
}

int defwOneViaEnd()
{
  defwFunc = DEFW_VIA;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState != DEFW_VIA) && (defwState != DEFW_VIAVIARULE)) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, " ;\n");
  defwLines++;

  defwState = DEFW_VIAONE_END;
  return DEFW_OK;
}

int defwEndVias()
{
  defwFunc = DEFW_VIA_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_VIA_START && defwState != DEFW_VIAONE_END) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, "END VIAS\n\n");
  defwLines++;

  defwState = DEFW_VIA_END;
  return DEFW_OK;
}

int defwStartRegions(int count)
{
  defwFunc = DEFW_REGION_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if ((defwState >= DEFW_REGION_START) && (defwState <= DEFW_REGION_END)) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row.
  }

  fprintf(defwFile, "REGIONS %d ;\n", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_REGION_START;
  return DEFW_OK;
}

int defwRegionName(const char* name)
{
  defwFunc = DEFW_REGION;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_REGION_START && defwState != DEFW_REGION) {
    return DEFW_BAD_ORDER;
  }
  defwCounter--;

  if (defwState == DEFW_REGION) {
    fprintf(defwFile, ";\n");  // add the ; and \n for the previous row.
  }

  if (!name || !*name) {  // required
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "   - %s ", name);
  defwState = DEFW_REGION;
  return DEFW_OK;
}

int defwRegionPoints(int xl, int yl, int xh, int yh)
{
  defwFunc = DEFW_REGION;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_REGION) {
    return DEFW_BAD_ORDER;  // after RegionName
  }

  fprintf(defwFile, "      ( %d %d ) ( %d %d ) ", xl, yl, xh, yh);

  defwState = DEFW_REGION;
  return DEFW_OK;
}

int defwRegionType(const char* type)
{
  defwFunc = DEFW_REGION;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_REGION) {
    return DEFW_BAD_ORDER;  // after RegionName
  }

  if (!type || !*type) {  // required
    return DEFW_BAD_DATA;
  }
  if (strcmp(type, "FENCE") && strcmp(type, "GUIDE")) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "         + TYPE %s ", type);

  defwState = DEFW_REGION;
  return DEFW_OK;
}

int defwEndRegions()
{
  defwFunc = DEFW_REGION_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_REGION_START && defwState != DEFW_REGION) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  if (defwState == DEFW_REGION) {
    fprintf(defwFile, ";\nEND REGIONS\n\n");  // ; for the previous statement
  } else {
    fprintf(defwFile, "END REGIONS\n\n");  // ; for the previous statement
  }
  defwLines++;

  defwState = DEFW_REGION_END;
  return DEFW_OK;
}

int defwComponentMaskShiftLayers(const char** layerNames, int numLayerName)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_COMPONENT_MASKSHIFTLAYERS;

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if (defwState == DEFW_COMPONENT_MASKSHIFTLAYERS) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "COMPONENTMASKSHIFT ");

  if (numLayerName) {
    for (int i = 0; i < numLayerName; i++) {
      fprintf(defwFile, "%s ", layerNames[i]);
    }
  }

  fprintf(defwFile, ";\n\n");

  defwLines++;

  defwState = DEFW_COMPONENT_MASKSHIFTLAYERS;
  return DEFW_OK;
}

int defwStartComponents(int count)
{
  defwFunc = DEFW_COMPONENT_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if ((defwState >= DEFW_COMPONENT_START)
      && (defwState <= DEFW_COMPONENT_END)) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row.
  }

  fprintf(defwFile, "COMPONENTS %d ;\n", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_COMPONENT_START;
  return DEFW_OK;
}

int defwComponent(const char* instance,
                  const char* master,
                  int numNetName,
                  const char** netNames,
                  const char* eeq,
                  const char* genName,
                  const char* genParemeters,
                  const char* source,
                  int numForeign,
                  const char** foreigns,
                  int* foreignX,
                  int* foreignY,
                  int* foreignOrients,
                  const char* status,
                  int statusX,
                  int statusY,
                  int statusOrient,
                  double weight,
                  const char* region,
                  int xl,
                  int yl,
                  int xh,
                  int yh)
{
  int i;
  int uplace = 0;

  defwFunc = DEFW_COMPONENT;  // Current function of writer

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_COMPONENT_START && defwState != DEFW_COMPONENT) {
    return DEFW_BAD_ORDER;
  }

  defwCounter--;

  // required
  if ((instance == nullptr) || (*instance == 0) || (master == nullptr)
      || (*master == 0)) {
    return DEFW_BAD_DATA;
  }

  if (source && strcmp(source, "NETLIST") && strcmp(source, "DIST")
      && strcmp(source, "USER") && strcmp(source, "TIMING")) {
    return DEFW_BAD_DATA;
  }

  if (status) {
    if (strcmp(status, "UNPLACED") == 0) {
      uplace = 1;
    } else if (strcmp(status, "COVER") && strcmp(status, "FIXED")
               && strcmp(status, "PLACED")) {
      return DEFW_BAD_DATA;
    }
  }

  // only either region or xl, yl, xh, yh
  if (region && (xl || yl || xh || yh)) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_COMPONENT) {
    fprintf(defwFile, ";\n");  // newline for the previous component
  }

  fprintf(defwFile, "   - %s %s ", instance, master);
  if (numNetName) {
    for (i = 0; i < numNetName; i++) {
      fprintf(defwFile, "%s ", netNames[i]);
    }
  }
  defwLines++;
  // since the rest is optionals, new line is placed before the options
  if (eeq) {
    fprintf(defwFile, "\n      + EEQMASTER %s ", eeq);
    defwLines++;
  }
  if (genName) {
    fprintf(defwFile, "\n      + GENERATE %s ", genName);
    if (genParemeters) {
      fprintf(defwFile, " %s ", genParemeters);
    }
    defwLines++;
  }
  if (source) {
    fprintf(defwFile, "\n      + SOURCE %s ", source);
    defwLines++;
  }
  if (numForeign) {
    for (i = 0; i < numForeign; i++) {
      fprintf(defwFile,
              "\n      + FOREIGN %s ( %d %d ) %s ",
              foreigns[i],
              foreignX[i],
              foreignY[i],
              defwOrient(foreignOrients[i]));
      defwLines++;
    }
  }
  if (status && (uplace == 0)) {
    fprintf(defwFile,
            "\n      + %s ( %d %d ) %s ",
            status,
            statusX,
            statusY,
            defwOrient(statusOrient));
  } else if (uplace) {
    fprintf(defwFile, "\n      + %s ", status);
  }
  defwLines++;
  if (weight) {
    fprintf(defwFile, "\n      + WEIGHT %.11g ", weight);
    defwLines++;
  }
  if (region) {
    fprintf(defwFile, "\n      + REGION %s ", region);
    defwLines++;
  } else if (xl || yl || xh || yh) {
    fprintf(defwFile, "\n      + REGION ( %d %d ) ( %d %d ) ", xl, yl, xh, yh);
    defwLines++;
  }

  defwState = DEFW_COMPONENT;
  return DEFW_OK;
}

int defwComponentStr(const char* instance,
                     const char* master,
                     int numNetName,
                     const char** netNames,
                     const char* eeq,
                     const char* genName,
                     const char* genParemeters,
                     const char* source,
                     int numForeign,
                     const char** foreigns,
                     int* foreignX,
                     int* foreignY,
                     const char** foreignOrients,
                     const char* status,
                     int statusX,
                     int statusY,
                     const char* statusOrient,
                     double weight,
                     const char* region,
                     int xl,
                     int yl,
                     int xh,
                     int yh)
{
  int i;
  int uplace = 0;

  defwFunc = DEFW_COMPONENT;  // Current function of writer

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_COMPONENT_START && defwState != DEFW_COMPONENT) {
    return DEFW_BAD_ORDER;
  }

  defwCounter--;

  if ((!instance || !*instance) || (!master || !*master)) {  // required
    return DEFW_BAD_DATA;
  }

  if (source && strcmp(source, "NETLIST") && strcmp(source, "DIST")
      && strcmp(source, "USER") && strcmp(source, "TIMING")) {
    return DEFW_BAD_DATA;
  }

  if (status) {
    if (strcmp(status, "UNPLACED") == 0) {
      uplace = 1;
    } else if (strcmp(status, "COVER") && strcmp(status, "FIXED")
               && strcmp(status, "PLACED")) {
      return DEFW_BAD_DATA;
    }
  }

  // only either region or xl, yl, xh, yh
  if (region && (xl || yl || xh || yh)) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_COMPONENT) {
    fprintf(defwFile, ";\n");  // newline for the previous component
  }

  fprintf(defwFile, "   - %s %s ", instance, master);
  if (numNetName) {
    for (i = 0; i < numNetName; i++) {
      fprintf(defwFile, "%s ", netNames[i]);
    }
  }
  defwLines++;
  // since the rest is optionals, new line is placed before the options
  if (eeq) {
    fprintf(defwFile, "\n      + EEQMASTER %s ", eeq);
    defwLines++;
  }
  if (genName) {
    fprintf(defwFile, "\n      + GENERATE %s ", genName);
    if (genParemeters) {
      fprintf(defwFile, " %s ", genParemeters);
    }
    defwLines++;
  }
  if (source) {
    fprintf(defwFile, "\n      + SOURCE %s ", source);
    defwLines++;
  }
  if (numForeign) {
    for (i = 0; i < numForeign; i++) {
      fprintf(defwFile,
              "\n      + FOREIGN %s ( %d %d ) %s ",
              foreigns[i],
              foreignX[i],
              foreignY[i],
              foreignOrients[i]);
      defwLines++;
    }
  }
  if (status && (uplace == 0)) {
    fprintf(defwFile,
            "\n      + %s ( %d %d ) %s ",
            status,
            statusX,
            statusY,
            statusOrient);
  } else if (uplace) {
    fprintf(defwFile, "\n      + %s ", status);
  }
  defwLines++;
  if (weight) {
    fprintf(defwFile, "\n      + WEIGHT %.11g ", weight);
    defwLines++;
  }
  if (region) {
    fprintf(defwFile, "\n      + REGION %s ", region);
    defwLines++;
  } else if (xl || yl || xh || yh) {
    fprintf(defwFile, "\n      + REGION ( %d %d ) ( %d %d ) ", xl, yl, xh, yh);
    defwLines++;
  }

  defwState = DEFW_COMPONENT;
  return DEFW_OK;
}

int defwComponentMaskShift(int shiftLayerMasks)
{
  defwFunc = DEFW_COMPONENT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  if (defwState != DEFW_COMPONENT) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + MASKSHIFT %d ", shiftLayerMasks);
  defwLines++;
  return DEFW_OK;
}

int defwComponentHalo(int left, int bottom, int right, int top)
{
  defwFunc = DEFW_COMPONENT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }
  if (defwState != DEFW_COMPONENT) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + HALO %d %d %d %d ", left, bottom, right, top);
  defwLines++;
  return DEFW_OK;
}

// 5.7
int defwComponentHaloSoft(int left, int bottom, int right, int top)
{
  defwFunc = DEFW_COMPONENT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defVersionNum < 5.7) {
    return DEFW_WRONG_VERSION;
  }
  if (defwState != DEFW_COMPONENT) {
    return DEFW_BAD_ORDER;
  }

  fprintf(
      defwFile, "\n      + HALO SOFT %d %d %d %d ", left, bottom, right, top);
  defwLines++;
  return DEFW_OK;
}

// 5.7
int defwComponentRouteHalo(int haloDist,
                           const char* minLayer,
                           const char* maxLayer)
{
  defwFunc = DEFW_COMPONENT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defVersionNum < 5.7) {
    return DEFW_WRONG_VERSION;
  }
  if (defwState != DEFW_COMPONENT) {
    return DEFW_BAD_ORDER;
  }

  fprintf(
      defwFile, "\n      + ROUTEHALO %d %s %s ", haloDist, minLayer, maxLayer);
  defwLines++;
  return DEFW_OK;
}

int defwEndComponents()
{
  defwFunc = DEFW_COMPONENT_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_COMPONENT_START && defwState != DEFW_COMPONENT) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  defwDidComponents = 1;

  if (defwState == DEFW_COMPONENT) {
    fprintf(defwFile, ";\nEND COMPONENTS\n\n");
  } else {
    fprintf(defwFile, "END COMPONENTS\n\n");
  }
  defwLines++;

  defwState = DEFW_COMPONENT_END;
  return DEFW_OK;
}

int defwStartPins(int count)
{
  defwFunc = DEFW_PIN_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidComponents) {
    return DEFW_BAD_ORDER;
  }
  if ((defwState >= DEFW_PIN_START) && (defwState <= DEFW_PIN_END)) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "PINS %d", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_PIN_START;
  return DEFW_OK;
}

int defwPin(const char* name,
            const char* net,
            int special,            // optional 0-ignore 1-special
            const char* direction,  // optional
            const char* use,        // optional
            const char* status,
            int xo,
            int yo,
            int orient,  // optional
            const char* layer,
            int xl,
            int yl,
            int xh,
            int yh  // optional
)
{
  defwFunc = DEFW_PIN;  // Current function of writer

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN_START && defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }

  defwCounter--;

  fprintf(defwFile, " ;\n   - %s + NET %s", name, net);

  if (special) {
    fprintf(defwFile, "\n      + SPECIAL");
  }
  if (direction) {
    if (strcmp(direction, "INPUT") && strcmp(direction, "OUTPUT")
        && strcmp(direction, "INOUT") && strcmp(direction, "FEEDTHRU")) {
      return DEFW_BAD_DATA;
    }
    fprintf(defwFile, "\n      + DIRECTION %s", direction);
  }
  if (use) {
    if (strcmp(use, "SIGNAL") && strcmp(use, "POWER") && strcmp(use, "GROUND")
        && strcmp(use, "CLOCK") && strcmp(use, "TIEOFF")
        && strcmp(use, "ANALOG") && strcmp(use, "SCAN")
        && strcmp(use, "RESET")) {
      return DEFW_BAD_DATA;
    }
    fprintf(defwFile, "\n      + USE %s", use);
  }
  if (status) {
    if (strcmp(status, "FIXED") && strcmp(status, "PLACED")
        && strcmp(status, "COVER")) {
      return DEFW_BAD_DATA;
    }

    fprintf(defwFile,
            "\n      + %s ( %d %d ) %s",
            status,
            xo,
            yo,
            defwOrient(orient));
  }
  // In 5.6, user should use defPinLayer to write out layer construct
  if (layer) {
    fprintf(defwFile,
            "\n      + LAYER %s ( %d %d ) ( %d %d )",
            layer,
            xl,
            yl,
            xh,
            yh);
  }

  defwLines++;

  defwState = DEFW_PIN;
  return DEFW_OK;
}

int defwPinStr(const char* name,
               const char* net,
               int special,            // optional 0-ignore 1-special
               const char* direction,  // optional
               const char* use,        // optional
               const char* status,
               int xo,
               int yo,
               const char* orient,  // optional
               const char* layer,
               int xl,
               int yl,
               int xh,
               int yh  // optional
)
{
  defwFunc = DEFW_PIN;  // Current function of writer

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN_START && defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }

  defwCounter--;

  fprintf(defwFile, " ;\n   - %s + NET %s", name, net);

  if (special) {
    fprintf(defwFile, "\n      + SPECIAL");
  }
  if (direction) {
    if (strcmp(direction, "INPUT") && strcmp(direction, "OUTPUT")
        && strcmp(direction, "INOUT") && strcmp(direction, "FEEDTHRU")) {
      return DEFW_BAD_DATA;
    }
    fprintf(defwFile, "\n      + DIRECTION %s", direction);
  }
  if (use) {
    if (strcmp(use, "SIGNAL") && strcmp(use, "POWER") && strcmp(use, "GROUND")
        && strcmp(use, "CLOCK") && strcmp(use, "TIEOFF")
        && strcmp(use, "ANALOG") && strcmp(use, "SCAN")
        && strcmp(use, "RESET")) {
      return DEFW_BAD_DATA;
    }
    fprintf(defwFile, "\n      + USE %s", use);
  }
  if (status) {
    if (strcmp(status, "FIXED") && strcmp(status, "PLACED")
        && strcmp(status, "COVER")) {
      return DEFW_BAD_DATA;
    }

    fprintf(defwFile, "\n      + %s ( %d %d ) %s", status, xo, yo, orient);
  }
  // In 5.6, user should use defPinLayer to write out layer construct
  if (layer) {
    fprintf(defwFile,
            "\n      + LAYER %s ( %d %d ) ( %d %d )",
            layer,
            xl,
            yl,
            xh,
            yh);
  }

  defwLines++;

  defwState = DEFW_PIN;
  return DEFW_OK;
}

int defwPinLayer(const char* layerName,
                 int spacing,
                 int designRuleWidth,
                 int xl,
                 int yl,
                 int xh,
                 int yh,
                 int mask)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }
  if (spacing && designRuleWidth) {
    return DEFW_BAD_DATA;  // only one, spacing
  }
  // or designRuleWidth can be defined, not both

  fprintf(defwFile, "\n      + LAYER %s ", layerName);

  if (mask) {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    fprintf(defwFile, "\n        MASK %d", mask);
  }

  if (spacing) {
    fprintf(defwFile, "\n        SPACING %d", spacing);
  } else if (designRuleWidth) {  // can be both 0
    fprintf(defwFile, "\n        DESIGNRULEWIDTH  %d", designRuleWidth);
  }
  fprintf(defwFile, "\n        ( %d %d ) ( %d %d )", xl, yl, xh, yh);

  defwState = DEFW_PIN;
  defwLines++;
  return DEFW_OK;
}

int defwPinPolygon(const char* layerName,
                   int spacing,
                   int designRuleWidth,
                   int num_polys,
                   double* xl,
                   double* yl,
                   int mask)
{
  int i;

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }
  if (spacing && designRuleWidth) {
    return DEFW_BAD_DATA;  // only one, spacing
  }
  // or designRuleWidth can be defined, not both

  fprintf(defwFile, "\n      + POLYGON %s ", layerName);

  if (mask) {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    fprintf(defwFile, "\n        MASK %d", mask);
  }

  if (spacing) {
    fprintf(defwFile, "\n        SPACING %d", spacing);
  } else if (designRuleWidth) {  // can be both 0
    fprintf(defwFile, "\n        DESIGNRULEWIDTH  %d", designRuleWidth);
  }

  printPointsNum = 0;

  for (i = 0; i < num_polys; i++) {
    if ((i == 0) || ((i % 5) == 0)) {
      printPoints(defwFile, *xl++, *yl++, "\n        ", " ");
      defwLines++;
    } else {
      printPoints(defwFile, *xl++, *yl++, "", " ");
    }
  }

  defwState = DEFW_PIN;
  defwLines++;
  return DEFW_OK;
}

// 5.7
int defwPinVia(const char* viaName, int xl, int yl, int mask)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.7) {
    return DEFW_WRONG_VERSION;
  }

  if (mask) {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    fprintf(
        defwFile, "\n      + VIA %s MASK %d ( %d %d ) ", viaName, mask, xl, yl);
  } else {
    fprintf(defwFile, "\n      + VIA %s ( %d %d ) ", viaName, xl, yl);
  }

  defwLines++;
  defwState = DEFW_PIN;
  return DEFW_OK;
}

// 5.7
int defwPinPort()
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.7) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + PORT");

  defwLines++;
  defwState = DEFW_PIN_PORT;
  return DEFW_OK;
}

// 5.7
int defwPinPortLayer(const char* layerName,
                     int spacing,
                     int designRuleWidth,
                     int xl,
                     int yl,
                     int xh,
                     int yh,
                     int mask)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN && defwState != DEFW_PIN_PORT) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.7) {
    return DEFW_WRONG_VERSION;
  }
  if (spacing && designRuleWidth) {
    return DEFW_BAD_DATA;  // only one, spacing
  }
  // or designRuleWidth can be defined, not both

  fprintf(defwFile, "\n        + LAYER %s ", layerName);

  if (mask) {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    fprintf(defwFile, "\n          MASK %d", mask);
  }

  if (spacing) {
    fprintf(defwFile, "\n          SPACING %d", spacing);
  } else if (designRuleWidth) {  // can be both 0
    fprintf(defwFile, "\n          DESIGNRULEWIDTH  %d", designRuleWidth);
  }

  fprintf(defwFile, "\n        ( %d %d ) ( %d %d )", xl, yl, xh, yh);

  defwState = DEFW_PIN;
  defwLines++;
  return DEFW_OK;
}

// 5.7
int defwPinPortPolygon(const char* layerName,
                       int spacing,
                       int designRuleWidth,
                       int num_polys,
                       double* xl,
                       double* yl,
                       int mask)
{
  int i;

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN && defwState != DEFW_PIN_PORT) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.7) {
    return DEFW_WRONG_VERSION;
  }
  if (spacing && designRuleWidth) {
    return DEFW_BAD_DATA;  // only one, spacing
  }
  // or designRuleWidth can be defined, not both

  fprintf(defwFile, "\n        + POLYGON %s ", layerName);

  if (mask) {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    fprintf(defwFile, "\n          MASK %d", mask);
  }

  if (spacing) {
    fprintf(defwFile, "\n          SPACING %d", spacing);
  } else if (designRuleWidth) {  // can be both 0
    fprintf(defwFile, "\n          DESIGNRULEWIDTH  %d", designRuleWidth);
  }

  printPointsNum = 0;
  for (i = 0; i < num_polys; i++) {
    if ((i == 0) || ((i % 5) == 0)) {
      printPoints(defwFile, *xl++, *yl++, "\n          ", " ");
      defwLines++;
    } else {
      printPoints(defwFile, *xl++, *yl++, "", " ");
    }
  }

  defwState = DEFW_PIN;
  defwLines++;
  return DEFW_OK;
}

// 5.7
int defwPinPortVia(const char* viaName, int xl, int yl, int mask)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN && defwState != DEFW_PIN_PORT) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.7) {
    return DEFW_WRONG_VERSION;
  }

  if (mask) {
    if (defVersionNum < 5.8) {
      return DEFW_WRONG_VERSION;
    }

    fprintf(defwFile,
            "\n        + VIA %s MASK %d ( %d %d ) ",
            viaName,
            mask,
            xl,
            yl);
  } else {
    fprintf(defwFile, "\n        + VIA %s ( %d %d ) ", viaName, xl, yl);
  }

  defwLines++;
  defwState = DEFW_PIN;
  return DEFW_OK;
}

// 5.7
int defwPinPortLocation(const char* status,
                        int statusX,
                        int statusY,
                        const char* orient)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN && defwState != DEFW_PIN_PORT) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.7) {
    return DEFW_WRONG_VERSION;
  }

  if (strcmp(status, "FIXED") && strcmp(status, "PLACED")
      && strcmp(status, "COVER")) {
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile,
          "\n        + %s ( %d %d ) %s ",
          status,
          statusX,
          statusY,
          orient);
  defwState = DEFW_PIN;
  defwLines++;
  return DEFW_OK;
}

int defwPinNetExpr(const char* pinExpr)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }
  if (pinExpr && pinExpr != nullptr && *pinExpr != 0) {
    fprintf(defwFile, "\n      + NETEXPR \"%s\"", pinExpr);
  }

  defwLines++;
  return DEFW_OK;
}

int defwPinSupplySensitivity(const char* pinName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }
  if (pinName && pinName != nullptr && *pinName != 0) {
    fprintf(defwFile, "\n      + SUPPLYSENSITIVITY %s", pinName);
  }

  defwLines++;
  return DEFW_OK;
}

int defwPinGroundSensitivity(const char* pinName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }
  if (pinName && pinName != nullptr && *pinName != 0) {
    fprintf(defwFile, "\n      + GROUNDSENSITIVITY %s", pinName);
  }

  defwLines++;
  return DEFW_OK;
}

int defwPinAntennaPinPartialMetalArea(int value, const char* layerName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAPINPARTIALMETALAREA %d", value);
  if (layerName) {
    fprintf(defwFile, " LAYER %s", layerName);
  }
  defwLines++;

  return DEFW_OK;
}

int defwPinAntennaPinPartialMetalSideArea(int value, const char* layerName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAPINPARTIALMETALSIDEAREA %d", value);
  if (layerName) {
    fprintf(defwFile, " LAYER %s", layerName);
  }
  defwLines++;

  return DEFW_OK;
}

int defwPinAntennaPinPartialCutArea(int value, const char* layerName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAPINPARTIALCUTAREA %d", value);
  if (layerName) {
    fprintf(defwFile, " LAYER %s", layerName);
  }
  defwLines++;

  return DEFW_OK;
}

int defwPinAntennaModel(const char* oxide)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAMODEL %s", oxide);
  defwLines++;

  return DEFW_OK;
}

int defwPinAntennaPinDiffArea(int value, const char* layerName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAPINDIFFAREA %d", value);
  if (layerName) {
    fprintf(defwFile, " LAYER %s", layerName);
  }
  defwLines++;

  return DEFW_OK;
}

int defwPinAntennaPinGateArea(int value, const char* layerName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAPINGATEAREA %d", value);
  if (layerName) {
    fprintf(defwFile, " LAYER %s", layerName);
  }
  defwLines++;

  return DEFW_OK;
}

int defwPinAntennaPinMaxAreaCar(int value, const char* layerName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAPINMAXAREACAR %d", value);
  if (!layerName) {
    return DEFW_BAD_DATA;  // layerName is required
  }

  fprintf(defwFile, " LAYER %s", layerName);
  defwLines++;

  return DEFW_OK;
}

int defwPinAntennaPinMaxSideAreaCar(int value, const char* layerName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAPINMAXSIDEAREACAR %d", value);
  if (!layerName) {
    return DEFW_BAD_DATA;  // layerName is required
  }

  fprintf(defwFile, " LAYER %s", layerName);
  defwLines++;

  return DEFW_OK;
}

int defwPinAntennaPinMaxCutCar(int value, const char* layerName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + ANTENNAPINMAXCUTCAR %d", value);
  if (!layerName) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, " LAYER %s", layerName);
  defwLines++;

  return DEFW_OK;
}

int defwEndPins()
{
  defwFunc = DEFW_PIN_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PIN_START && defwState != DEFW_PIN) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, " ;\nEND PINS\n\n");
  defwLines++;

  defwState = DEFW_PIN_END;
  return DEFW_OK;
}

int defwStartPinProperties(int count)
{
  defwFunc = DEFW_PINPROP_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_PINPROP_START) && (defwState <= DEFW_PINPROP_END)) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "PINPROPERTIES %d ;\n", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_PINPROP_START;
  return DEFW_OK;
}

int defwPinProperty(const char* name, const char* pinName)
{
  defwFunc = DEFW_PINPROP;  // Current function of writer

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PINPROP_START && defwState != DEFW_PINPROP) {
    return DEFW_BAD_ORDER;
  }

  defwCounter--;
  if ((!name || !*name) || (!pinName || !*pinName)) {  // required
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_PINPROP) {
    fprintf(defwFile, ";\n");
  }

  fprintf(defwFile, "   - %s %s ", name, pinName);
  defwLines++;

  defwState = DEFW_PINPROP;
  return DEFW_OK;
}

int defwEndPinProperties()
{
  defwFunc = DEFW_PIN_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PINPROP_START && defwState != DEFW_PINPROP) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  if (defwState == DEFW_PINPROP_START) {
    fprintf(defwFile, "END PINPROPERTIES\n\n");
  } else {
    fprintf(defwFile, ";\nEND PINPROPERTIES\n\n");
  }
  defwLines++;

  defwState = DEFW_PINPROP_END;
  return DEFW_OK;
}

int defwStartSpecialNets(int count)
{
  defwFunc = DEFW_SNET_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_SNET_START) && (defwState <= DEFW_SNET_END)) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "SPECIALNETS %d ;\n", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_SNET_START;
  return DEFW_OK;
}

int defwSpecialNetOptions()
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (defwState == DEFW_SNET) {
    defwState = DEFW_SNET_OPTIONS;
    return 1;
  }
  if (defwState == DEFW_SNET_OPTIONS) {
    return 1;
  }
  return 0;
}

int defwSpecialNet(const char* name)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SNET_START && defwState != DEFW_SNET_ENDNET) {
    return DEFW_BAD_ORDER;
  }
  defwState = DEFW_SNET;

  fprintf(defwFile, "   - %s", name);
  defwLineItemCounter = 0;
  defwCounter--;

  return DEFW_OK;
}

int defwSpecialNetConnection(const char* inst, const char* pin, int synthesized)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SNET) {
    return DEFW_BAD_ORDER;
  }

  if ((++defwLineItemCounter & 3) == 0) {  // since a net can have more than
    fprintf(defwFile, "\n     ");  // one inst pin connection, don't print
    defwLines++;                   // newline until the line is certain length
  }
  fprintf(defwFile, " ( %s %s ", inst, pin);
  if (synthesized) {
    fprintf(defwFile, " + SYNTHESIZED ");
  }
  fprintf(defwFile, ") ");
  return DEFW_OK;
}

int defwSpecialNetFixedbump()
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + FIXEDBUMP");
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetVoltage(double d)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  int v = (int) (d * 1000);

  fprintf(defwFile, "\n      + VOLTAGE %d", v);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetSpacing(const char* layer,
                          int spacing,
                          double minwidth,
                          double maxwidth)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + SPACING %s %d", layer, spacing);
  if (minwidth || maxwidth) {
    fprintf(defwFile, " RANGE %.11g %.11g", minwidth, maxwidth);
  }
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetWidth(const char* layer, int w)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + WIDTH %s %d", layer, w);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetSource(const char* name)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + SOURCE %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetOriginal(const char* name)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + ORIGINAL %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetPattern(const char* name)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + PATTERN %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetUse(const char* name)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  if (strcmp(name, "SIGNAL") && strcmp(name, "POWER") && strcmp(name, "GROUND")
      && strcmp(name, "CLOCK") && strcmp(name, "TIEOFF")
      && strcmp(name, "ANALOG") && strcmp(name, "SCAN")
      && strcmp(name, "RESET")) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + USE %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetWeight(double d)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + WEIGHT %.11g", d);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetEstCap(double d)
{
  defwFunc = DEFW_SNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + ESTCAP %.11g", d);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetPathStart(const char* typ)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions() && (defwState != DEFW_SUBNET)
      &&                           // path in subnet
      (defwState != DEFW_PATH)) {  // NEW in the path, path hasn't end yet
    return DEFW_BAD_ORDER;
  }

  if (strcmp(typ, "NEW") && strcmp(typ, "FIXED") && strcmp(typ, "COVER")
      && strcmp(typ, "ROUTED") && strcmp(typ, "SHIELD")) {
    return DEFW_BAD_DATA;
  }

  defwSpNetShield = 0;

  // The second time around for a path on this net, we
  // must start it with a new instead of a fixed...
  if (strcmp(typ, "NEW") == 0) {
    if (defwState != DEFW_PATH) {
      return DEFW_BAD_DATA;
    }
    fprintf(defwFile, " NEW");
  } else if (strcmp(typ, "SHIELD") == 0) {
    fprintf(defwFile, "\n      + %s", typ);
    defwSpNetShield = 1;
  } else {
    fprintf(defwFile, "\n      + %s", typ);
  }

  defwState = DEFW_PATH_START;
  defwLineItemCounter = 0;
  return DEFW_OK;
}

int defwSpecialNetShieldNetName(const char* name)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH_START) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  if (defwSpNetShield) {
    fprintf(defwFile, " %s", name);
  } else {
    return DEFW_BAD_ORDER;
  }
  return DEFW_OK;
}

int defwSpecialNetPathWidth(int w)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " %d", w);
  return DEFW_OK;
}

int defwSpecialNetPathLayer(const char* name)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH_START) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " %s", name);
  defwState = DEFW_PATH;
  return DEFW_OK;
}

int defwSpecialNetPathStyle(int styleNum)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }

  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, "\n      + STYLE %d", styleNum);
  defwState = DEFW_PATH;
  defwLineItemCounter = 0;
  return DEFW_OK;
}

int defwSpecialNetPathShape(const char* typ)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }

  if (strcmp(typ, "RING") && strcmp(typ, "STRIPE") && strcmp(typ, "FOLLOWPIN")
      && strcmp(typ, "IOWIRE") && strcmp(typ, "COREWIRE")
      && strcmp(typ, "BLOCKWIRE") && strcmp(typ, "FILLWIRE")
      && strcmp(typ, "BLOCKAGEWIRE") && strcmp(typ, "PADRING")
      && strcmp(typ, "BLOCKRING") && strcmp(typ, "DRCFILL")
      && strcmp(typ, "FILLWIREOPC")) {  // 5.7
    return DEFW_BAD_DATA;
  }

  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, "\n      + SHAPE %s", typ);

  defwState = DEFW_PATH;
  defwLineItemCounter = 0;
  return DEFW_OK;
}

int defwSpecialNetPathMask(int colorMask)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_PATH;  // Current function of writer

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " MASK %d", colorMask);
  return DEFW_OK;
}

int defwSpecialNetPathPoint(int numPts, double* pointx, double* pointy)
{
  int i;

  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }

  printPointsNum = 0;
  for (i = 0; i < numPts; i++) {
    if ((++defwLineItemCounter & 3) == 0) {
      fprintf(defwFile, "\n     ");
      defwLines++;
    }

    printPoints(defwFile, pointx[i], pointy[i], " ", "");
  }
  return DEFW_OK;
}

int defwSpecialNetPathVia(const char* name)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " %s", name);
  return DEFW_OK;
}

int defwSpecialNetPathViaData(int numX, int numY, int stepX, int stepY)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " DO %d BY %d STEP %d %d", numX, numY, stepX, stepY);
  return DEFW_OK;
}

int defwSpecialNetPathPointWithWireExt(int numPts,
                                       double* pointx,
                                       double* pointy,
                                       double* optValue)
{
  int i;
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  for (i = 0; i < numPts; i++) {
    if ((++defwLineItemCounter & 3) == 0) {
      fprintf(defwFile, "\n        ");
      defwLines++;
    }
    fprintf(defwFile, " ( %.11g %.11g ", pointx[i], pointy[i]);
    if (optValue[i]) {
      fprintf(defwFile, "%.11g ", optValue[i]);
    }
    fprintf(defwFile, ")");
  }
  return DEFW_OK;
}

int defwSpecialNetPathEnd()
{
  defwFunc = DEFW_SNET_OPTIONS;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  defwState = DEFW_SNET_OPTIONS;
  return DEFW_OK;
}

int defwSpecialNetPolygon(const char* layerName,
                          int num_polys,
                          double* xl,
                          double* yl)
{
  int i;

  defwFunc = DEFW_SNET_OPTIONS;  // Current function of writer
  if (!defwSpecialNetOptions()
      && (defwState != DEFW_PATH)) {  // not inside a path
    return DEFW_BAD_ORDER;
  }

  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + POLYGON %s ", layerName);

  printPointsNum = 0;
  for (i = 0; i < num_polys; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      printPoints(defwFile, *xl++, *yl++, "", " ");
    } else {
      printPoints(defwFile, *xl++, *yl++, "\n                ", " ");
      defwLines++;
    }
  }
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetMask(int colorMask)
{
  defwFunc = DEFW_SNET_OPTIONS;  // Current function of writer
  if (!defwSpecialNetOptions()
      && (defwState != DEFW_PATH)) {  // not inside a path
    return DEFW_BAD_ORDER;
  }

  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + MASK %d ", colorMask);

  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetRect(const char* layerName, int xl, int yl, int xh, int yh)
{
  defwFunc = DEFW_SNET_OPTIONS;  // Current function of writer
  if (!defwSpecialNetOptions()
      && (defwState != DEFW_PATH)) {  // not inside a path
    return DEFW_BAD_ORDER;
  }

  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile,
          "\n      + RECT %s ( %d %d ) ( %d %d ) ",
          layerName,
          xl,
          yl,
          xh,
          yh);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetVia(const char* layerName)
{
  defwFunc = DEFW_SNET_OPTIONS;  // Current function of writer
  if (!defwSpecialNetOptions()
      && (defwState != DEFW_PATH)) {  // not inside a path
    return DEFW_BAD_ORDER;
  }

  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + VIA %s ", layerName);
  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetViaWithOrient(const char* layerName, int orient)
{
  defwFunc = DEFW_SNET_OPTIONS;  // Current function of writer
  if (!defwSpecialNetOptions()
      && (defwState != DEFW_PATH)) {  // not inside a path
    return DEFW_BAD_ORDER;
  }

  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "\n      + VIA %s %s", layerName, defwOrient(orient));

  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetViaPoints(int num_points, double* xl, double* yl)
{
  defwFunc = DEFW_SNET_OPTIONS;  // Current function of writer
  if (!defwSpecialNetOptions()
      && (defwState != DEFW_PATH)) {  // not inside a path
    return DEFW_BAD_ORDER;
  }

  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  printPointsNum = 0;
  for (int i = 0; i < num_points; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      printPoints(defwFile, *xl++, *yl++, "", " ");
    } else {
      printPoints(defwFile, *xl++, *yl++, "\n             ", " ");
      defwLines++;
    }
  }

  defwLines++;
  return DEFW_OK;
}

int defwSpecialNetShieldStart(const char* name)
{
  defwFunc = DEFW_SHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  // The second time around for a shield on this net, we
  // must start it with a new instead of the name ...
  if (strcmp(name, "NEW") == 0) {
    if (defwState != DEFW_SHIELD) {
      return DEFW_BAD_DATA;
    }
    fprintf(defwFile, " NEW");
  } else {
    fprintf(defwFile, "\n      + SHIELD %s", name);
  }

  defwState = DEFW_SHIELD;
  defwLineItemCounter = 0;
  return DEFW_OK;
}

int defwSpecialNetShieldWidth(int w)
{
  defwFunc = DEFW_SHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SHIELD) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " %d", w);
  return DEFW_OK;
}

int defwSpecialNetShieldLayer(const char* name)
{
  defwFunc = DEFW_SHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SHIELD) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " %s", name);
  return DEFW_OK;
}

int defwSpecialNetShieldShape(const char* typ)
{
  defwFunc = DEFW_SHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SHIELD) {
    return DEFW_BAD_ORDER;
  }

  if (strcmp(typ, "RING") && strcmp(typ, "STRIPE") && strcmp(typ, "FOLLOWPIN")
      && strcmp(typ, "IOWIRE") && strcmp(typ, "COREWIRE")
      && strcmp(typ, "BLOCKWIRE") && strcmp(typ, "FILLWIRE")
      && strcmp(typ, "BLOCKAGEWIRE") && strcmp(typ, "DRCFILL")) {
    return DEFW_BAD_DATA;
  }

  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, "\n      + SHAPE %s", typ);

  defwState = DEFW_SHIELD;
  defwLineItemCounter = 0;
  return DEFW_OK;
}

int defwSpecialNetShieldPoint(int numPts, double* pointx, double* pointy)
{
  int i;

  defwFunc = DEFW_SHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SHIELD) {
    return DEFW_BAD_ORDER;
  }

  printPointsNum = 0;
  for (i = 0; i < numPts; i++) {
    if ((++defwLineItemCounter & 3) == 0) {
      fprintf(defwFile, "\n     ");
      defwLines++;
    }
    printPoints(defwFile, pointx[i], pointy[i], " ", "");
  }
  return DEFW_OK;
}

int defwSpecialNetShieldVia(const char* name)
{
  defwFunc = DEFW_SHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SHIELD) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " %s", name);
  return DEFW_OK;
}

int defwSpecialNetShieldViaData(int numX, int numY, int stepX, int stepY)
{
  defwFunc = DEFW_SHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SHIELD) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " DO %d BY %d STEP %d %d", numX, numY, stepX, stepY);
  return DEFW_OK;
}

int defwSpecialNetShieldEnd()
{
  defwFunc = DEFW_SNET_OPTIONS;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SHIELD) {
    return DEFW_BAD_ORDER;
  }
  defwState = DEFW_SNET_OPTIONS;
  return DEFW_OK;
}

int defwSpecialNetEndOneNet()
{
  defwFunc = DEFW_SNET_ENDNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwSpecialNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, " ;\n");
  defwLines++;
  defwState = DEFW_SNET_ENDNET;

  return DEFW_OK;
}

int defwEndSpecialNets()
{
  defwFunc = DEFW_SNET_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SNET_START && defwState != DEFW_SNET_OPTIONS
      && defwState != DEFW_SNET_ENDNET &&  // last state is special net
      defwState != DEFW_SNET) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, "END SPECIALNETS\n\n");
  defwLines++;

  defwState = DEFW_SNET_END;
  return DEFW_OK;
}

int defwStartNets(int count)
{
  defwFunc = DEFW_NET_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_NET_START) && (defwState <= DEFW_NET_END)) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "NETS %d ;\n", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_NET_START;
  return DEFW_OK;
}

int defwNetOptions()
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (defwState == DEFW_NET) {
    defwState = DEFW_NET_OPTIONS;
    return 1;
  }
  if (defwState == DEFW_NET_OPTIONS) {
    return 1;
  }
  return 0;
}

int defwNet(const char* name)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_NET_START && defwState != DEFW_NET_ENDNET) {
    return DEFW_BAD_ORDER;
  }
  defwState = DEFW_NET;

  fprintf(defwFile, "   - %s", name);
  defwLineItemCounter = 0;
  defwCounter--;

  return DEFW_OK;
}

int defwNetConnection(const char* inst, const char* pin, int synthesized)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_NET) {
    return DEFW_BAD_ORDER;
  }

  if ((++defwLineItemCounter & 3) == 0) {  // since there is more than one
    fprintf(defwFile, "\n");  // inst & pin connection, don't print newline
    defwLines++;              // until the line is certain length long
  }
  fprintf(defwFile, " ( %s %s", inst, pin);
  if (synthesized) {
    fprintf(defwFile, " + SYNTHESIZED ) ");
  } else {
    fprintf(defwFile, " ) ");
  }
  return DEFW_OK;
}

int defwNetMustjoinConnection(const char* inst, const char* pin)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_NET_ENDNET) {
    return DEFW_BAD_ORDER;
  }

  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " - MUSTJOIN ( %s %s )", inst, pin);

  defwState = DEFW_NET;

  defwCounter--;

  return DEFW_OK;
}

int defwNetFixedbump()
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + FIXEDBUMP");
  defwLines++;
  return DEFW_OK;
}

int defwNetFrequency(double frequency)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + FREQUENCY %.11g", frequency);
  defwLines++;
  return DEFW_OK;
}

int defwNetSource(const char* name)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + SOURCE %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwNetXtalk(int xtalk)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + XTALK %d", xtalk);
  defwLines++;
  return DEFW_OK;
}

int defwNetVpin(const char* vpinName,
                const char* layerName,
                int layerXl,
                int layerYl,
                int layerXh,
                int layerYh,
                const char* status,
                int statusX,
                int statusY,
                int orient)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }
  if ((vpinName == nullptr) || (*vpinName == 0)) {  // required
    return DEFW_BAD_DATA;
  }

  if (status && strcmp(status, "PLACED") && strcmp(status, "FIXED")
      && strcmp(status, "COVER")) {
    return DEFW_BAD_DATA;
  }
  if (status && (orient == 1)) {  // require if status is set
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + VPIN %s", vpinName);
  if (layerName) {
    fprintf(defwFile, " LAYER %s", layerName);
  }
  fprintf(
      defwFile, " ( %d %d ) ( %d %d )\n", layerXl, layerYl, layerXh, layerYh);
  defwLines++;

  if (status) {
    fprintf(defwFile,
            "         %s ( %d %d ) %s",
            status,
            statusX,
            statusY,
            defwOrient(orient));
  }
  defwLines++;
  return DEFW_OK;
}

int defwNetVpinStr(const char* vpinName,
                   const char* layerName,
                   int layerXl,
                   int layerYl,
                   int layerXh,
                   int layerYh,
                   const char* status,
                   int statusX,
                   int statusY,
                   const char* orient)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }
  if (!vpinName || !*vpinName) {  // required
    return DEFW_BAD_DATA;
  }

  if (status && strcmp(status, "PLACED") && strcmp(status, "FIXED")
      && strcmp(status, "COVER")) {
    return DEFW_BAD_DATA;
  }
  if (status && orient && *orient == '\0') {  // require if status is set
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + VPIN %s", vpinName);
  if (layerName) {
    fprintf(defwFile, " LAYER %s", layerName);
  }
  fprintf(
      defwFile, " ( %d %d ) ( %d %d )\n", layerXl, layerYl, layerXh, layerYh);
  defwLines++;

  if (status) {
    fprintf(
        defwFile, "         %s ( %d %d ) %s", status, statusX, statusY, orient);
  }
  defwLines++;
  return DEFW_OK;
}

int defwNetOriginal(const char* name)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + ORIGINAL %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwNetPattern(const char* name)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + PATTERN %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwNetUse(const char* name)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  if (strcmp(name, "SIGNAL") && strcmp(name, "POWER") && strcmp(name, "GROUND")
      && strcmp(name, "CLOCK") && strcmp(name, "TIEOFF")
      && strcmp(name, "ANALOG") && strcmp(name, "SCAN")
      && strcmp(name, "RESET")) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + USE %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwNetNondefaultRule(const char* name)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState != DEFW_NET) && (defwState != DEFW_NET_OPTIONS)
      && (defwState != DEFW_SUBNET)) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_SUBNET) {
    fprintf(defwFile, "\n         NONDEFAULTRULE %s", name);
  } else {
    fprintf(defwFile, "\n      + NONDEFAULTRULE %s", name);
  }
  defwLines++;
  return DEFW_OK;
}

int defwNetWeight(double d)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + WEIGHT %.11g", d);
  defwLines++;
  return DEFW_OK;
}

int defwNetEstCap(double d)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + ESTCAP %.11g", d);
  defwLines++;
  return DEFW_OK;
}

int defwNetShieldnet(const char* name)
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "\n      + SHIELDNET %s", name);
  defwLines++;
  return DEFW_OK;
}

int defwNetNoshieldStart(const char* name)
{
  defwFunc = DEFW_NOSHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }
  fprintf(defwFile, "\n      + NOSHIELD %s", name);

  defwState = DEFW_NOSHIELD;
  defwLineItemCounter = 0;
  return DEFW_OK;
}

int defwNetNoshieldPoint(int numPts, const char** pointx, const char** pointy)
{
  int i;

  defwFunc = DEFW_NOSHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_NOSHIELD) {
    return DEFW_BAD_ORDER;
  }
  for (i = 0; i < numPts; i++) {
    if ((++defwLineItemCounter & 3) == 0) {
      fprintf(defwFile, "\n     ");
      defwLines++;
    }
    fprintf(defwFile, " ( %s %s )", pointx[i], pointy[i]);
  }
  return DEFW_OK;
}

int defwNetNoshieldVia(const char* name)
{
  defwFunc = DEFW_NOSHIELD;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_NOSHIELD) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " %s", name);
  return DEFW_OK;
}

int defwNetNoshieldEnd()
{
  defwFunc = DEFW_NET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_NOSHIELD) {
    return DEFW_BAD_ORDER;
  }
  defwState = DEFW_NET;
  return DEFW_OK;
}

int defwNetSubnetStart(const char* name)
{
  defwFunc = DEFW_SUBNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }
  if (!name || !*name) {  // required
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + SUBNET %s", name);
  defwLines++;
  defwState = DEFW_SUBNET;
  defwLineItemCounter = 0;
  return DEFW_OK;
}

int defwNetSubnetPin(const char* compName, const char* pinName)
{
  defwFunc = DEFW_SUBNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SUBNET) {
    return DEFW_BAD_ORDER;
  }
  if ((!compName || !*compName) || (!pinName || !*pinName)) {  // required
    return DEFW_BAD_DATA;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n        ");
    defwLines++;
  }
  fprintf(defwFile, " ( %s %s )", compName, pinName);
  defwLines++;
  return DEFW_OK;
}

int defwNetSubnetEnd()
{
  defwFunc = DEFW_SUBNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState != DEFW_SUBNET) &&       // subnet does not have path
      (defwState != DEFW_NET_OPTIONS)) {  // subnet has path and path just ended
    return DEFW_BAD_ORDER;
  }
  defwState = DEFW_NET_OPTIONS;
  return DEFW_OK;
}

int defwNetPathStart(const char* typ)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions() && (defwState != DEFW_SUBNET) &&  // path in subnet
      (defwState != DEFW_PATH)) {  // NEW in the path, path hasn't end yet
    return DEFW_BAD_ORDER;
  }

  if (strcmp(typ, "NEW") && strcmp(typ, "FIXED") && strcmp(typ, "COVER")
      && strcmp(typ, "ROUTED") && strcmp(typ, "NOSHIELD")) {
    return DEFW_BAD_DATA;
  }

  // The second time around for a path on this net, we
  // must start it with a new instead of a fixed...
  if (strcmp(typ, "NEW") == 0) {
    if (defwState != DEFW_PATH) {
      return DEFW_BAD_DATA;
    }
    fprintf(defwFile, "\n         NEW");
  } else {
    if (defwState == DEFW_SUBNET) {
      fprintf(defwFile, "\n      %s", typ);
    } else {
      fprintf(defwFile, "\n      + %s", typ);
    }
  }

  defwState = DEFW_PATH_START;
  defwLineItemCounter = 0;
  return DEFW_OK;
}

int defwNetPathWidth(int w)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n         ");
    defwLines++;
  }
  fprintf(defwFile, " %d", w);
  return DEFW_OK;
}

int defwNetPathLayer(const char* name, int isTaper, const char* ruleName)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH_START) {
    return DEFW_BAD_ORDER;
  }

  // only one, either isTaper or ruleName can be set
  if (isTaper && ruleName) {
    return DEFW_BAD_DATA;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n        ");
    defwLines++;
  }
  fprintf(defwFile, " %s", name);
  if (isTaper) {
    fprintf(defwFile, " TAPER");
  } else if (ruleName) {
    fprintf(defwFile, " TAPERRULE %s", ruleName);
  }
  defwState = DEFW_PATH;
  return DEFW_OK;
}

int defwNetPathStyle(int styleNum)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, " STYLE %d", styleNum);
  return DEFW_OK;
}

int defwNetPathPoint(int numPts, double* pointx, double* pointy)
{
  int i;
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }

  printPointsNum = 0;
  for (i = 0; i < numPts; i++) {
    if ((++defwLineItemCounter & 3) == 0) {
      fprintf(defwFile, "\n        ");
      defwLines++;
    }
    printPoints(defwFile, pointx[i], pointy[i], " ", "");
  }
  return DEFW_OK;
}

int defwNetPathPointWithExt(int numPts,
                            double* pointx,
                            double* pointy,
                            double* optValue)
{
  int i;
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  for (i = 0; i < numPts; i++) {
    if ((++defwLineItemCounter & 3) == 0) {
      fprintf(defwFile, "\n        ");
      defwLines++;
    }
    fprintf(
        defwFile, " ( %.11g %.11g %.11g )", pointx[i], pointy[i], optValue[i]);
  }
  return DEFW_OK;
}

int defwNetPathVia(const char* name)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n        ");
    defwLines++;
  }
  if (!name || !*name) {  // required
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, " %s", name);
  return DEFW_OK;
}

int defwNetPathViaWithOrient(const char* name, int orient)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n        ");
    defwLines++;
  }

  if (!name || !*name) {  // required
    return DEFW_BAD_DATA;
  }

  if (orient == -1) {
    fprintf(defwFile, " %s", name);
  } else if (orient >= 0 && orient <= 7) {
    fprintf(defwFile, " %s %s", name, defwOrient(orient));
  } else {
    return DEFW_BAD_DATA;
  }
  return DEFW_OK;
}

int defwNetPathViaWithOrientStr(const char* name, const char* orient)
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n        ");
    defwLines++;
  }

  if (!name || !*name) {  // required
    return DEFW_BAD_DATA;
  }

  if (!orient || !*orient) {
    fprintf(defwFile, " %s", name);
  } else {
    fprintf(defwFile, " %s %s", name, orient);
  }
  return DEFW_OK;
}

int defwNetPathMask(int colorMask)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " MASK %d", colorMask);
  return DEFW_OK;
}

int defwNetPathRect(int deltaX1, int deltaY1, int deltaX2, int deltaY2)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }

  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }

  fprintf(
      defwFile, " RECT ( %d %d %d %d )", deltaX1, deltaY1, deltaX2, deltaY2);

  return DEFW_OK;
}

int defwNetPathVirtual(int x, int y)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  if ((++defwLineItemCounter & 3) == 0) {
    fprintf(defwFile, "\n     ");
    defwLines++;
  }
  fprintf(defwFile, " VIRTUAL ( %d %d )", x, y);
  return DEFW_OK;
}

int defwNetPathEnd()
{
  defwFunc = DEFW_PATH;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_PATH) {
    return DEFW_BAD_ORDER;
  }
  defwState = DEFW_NET_OPTIONS;
  return DEFW_OK;
}

int defwNetEndOneNet()
{
  defwFunc = DEFW_NET_ENDNET;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwNetOptions()) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, " ;\n");
  defwLines++;
  defwState = DEFW_NET_ENDNET;

  return DEFW_OK;
}

int defwEndNets()
{
  defwFunc = DEFW_NET_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_NET_START && defwState != DEFW_NET_OPTIONS
      && defwState != DEFW_NET
      && defwState != DEFW_NET_ENDNET) {  // last state is a net
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, "END NETS\n\n");
  defwLines++;

  defwState = DEFW_NET_END;
  defwDidNets = 1;
  return DEFW_OK;
}

int defwStartIOTimings(int count)
{
  defwObsoleteNum = DEFW_IOTIMING_START;
  defwFunc = DEFW_IOTIMING_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidNets) {
    return DEFW_BAD_ORDER;
  }
  if ((defwState >= DEFW_IOTIMING_START) && (defwState >= DEFW_IOTIMING_END)) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum >= 5.4) {
    return DEFW_OBSOLETE;
  }

  fprintf(defwFile, "IOTIMINGS %d ;\n", count);
  defwLines++;

  defwCounter = count;
  defwState = DEFW_IOTIMING_START;
  return DEFW_OK;
}

int defwIOTiming(const char* instance, const char* pin)
{
  defwFunc = DEFW_IOTIMING;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_IOTIMING_START && defwState != DEFW_IOTIMING) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_IOTIMING) {
    fprintf(defwFile, " ;\n");  // from previous statement
  }
  fprintf(defwFile, "   - ( %s %s )\n", instance, pin);
  defwLines++;

  defwCounter--;
  defwState = DEFW_IOTIMING;
  return DEFW_OK;
}

int defwIOTimingVariable(const char* riseFall, int num1, int num2)
{
  defwFunc = DEFW_IOTIMING;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_IOTIMING) {
    return DEFW_BAD_ORDER;
  }

  if (strcmp(riseFall, "RISE") && strcmp(riseFall, "FALL")) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "      + %s VARIABLE %d %d\n", riseFall, num1, num2);
  defwLines++;

  return DEFW_OK;
}

int defwIOTimingSlewrate(const char* riseFall, int num1, int num2)
{
  defwFunc = DEFW_IOTIMING;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_IOTIMING) {
    return DEFW_BAD_ORDER;
  }

  if (strcmp(riseFall, "RISE") && strcmp(riseFall, "FALL")) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "      + %s SLEWRATE %d %d\n", riseFall, num1, num2);
  defwLines++;

  return DEFW_OK;
}

int defwIOTimingDrivecell(const char* name,
                          const char* fromPin,
                          const char* toPin,
                          int numDrivers)
{
  defwFunc = DEFW_IOTIMING;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_IOTIMING) {
    return DEFW_BAD_ORDER;
  }
  if (!name || !*name) {  // required
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "      + DRIVECELL %s ", name);
  if (fromPin && (!toPin || !*toPin)) {  // if have fromPin, toPin is required
    return DEFW_BAD_DATA;
  }
  if (fromPin) {
    fprintf(defwFile, "FROMPIN %s ", fromPin);
  }
  if (toPin) {
    fprintf(defwFile, "TOPIN %s ", toPin);
  }
  if (numDrivers) {
    fprintf(defwFile, "PARALLEL %d ", numDrivers);
  }
  defwLines++;

  return DEFW_OK;
}

int defwIOTimingCapacitance(double num)
{
  defwFunc = DEFW_IOTIMING;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_IOTIMING) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "      + CAPACITANCE %.11g", num);
  defwLines++;

  return DEFW_OK;
}

int defwEndIOTimings()
{
  defwFunc = DEFW_IOTIMING_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_IOTIMING_START && defwState != DEFW_IOTIMING) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  if (defwState == DEFW_IOTIMING) {
    fprintf(defwFile, " ;\n");  // from previous statement
  }
  fprintf(defwFile, "END IOTIMINGS\n\n");
  defwLines++;

  defwState = DEFW_IOTIMING_END;
  return DEFW_OK;
}

int defwStartScanchains(int count)
{
  defwFunc = DEFW_SCANCHAIN_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidNets) {
    return DEFW_BAD_ORDER;
  }
  if ((defwState >= DEFW_SCANCHAIN_START)
      && (defwState <= DEFW_SCANCHAIN_END)) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "SCANCHAINS %d ;\n", count);
  defwLines++;

  defwState = DEFW_SCANCHAIN_START;
  defwCounter = count;
  return DEFW_OK;
}

int defwScanchain(const char* name)
{
  defwFunc = DEFW_SCANCHAIN;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_SCANCHAIN || defwState == DEFW_SCAN_FLOATING
      || defwState
             == DEFW_SCAN_ORDERED) {  // put a ; for the previous scanchain
    fprintf(defwFile, " ;\n");
  }

  fprintf(defwFile, "   - %s", name);
  defwLines++;

  defwCounter--;
  defwState = DEFW_SCANCHAIN;
  return DEFW_OK;
}

int defwScanchainCommonscanpins(const char* inst1,
                                const char* pin1,
                                const char* inst2,
                                const char* pin2)
{
  defwFunc = DEFW_SCANCHAIN;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (!inst1) {  // if inst1 is null, nothing will be written
    defwState = DEFW_SCANCHAIN;
    return DEFW_OK;
  }

  if (inst1 && strcmp(inst1, "IN") && strcmp(inst1, "OUT")) {  // IN | OUT
    return DEFW_BAD_DATA;
  }

  if (inst1 && !pin1) {  // pin1 can't be NULL if inst1 is not
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + COMMONSCANPINS ( %s %s )", inst1, pin1);

  if (inst2 && !pin2) {  // pin2 can't be NULL if inst2 is not
    return DEFW_BAD_DATA;
  }

  if (inst2 && strcmp(inst2, "IN") && strcmp(inst2, "OUT")) {  // IN | OUT
    return DEFW_BAD_DATA;
  }

  if (inst2) {
    fprintf(defwFile, " ( %s %s )", inst2, pin2);
  }

  defwLines++;

  defwState = DEFW_SCANCHAIN;
  return DEFW_OK;
}

int defwScanchainPartition(const char* name, int maxBits)
{
  defwFunc = DEFW_SCANCHAIN;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (!name || !*name) {  // require
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + PARTITION %s", name);
  if (maxBits != -1) {
    fprintf(defwFile, " MAXBITS %d", maxBits);
  }
  defwLines++;

  defwState = DEFW_SCANCHAIN;
  return DEFW_OK;
}

int defwScanchainStart(const char* inst, const char* pin)
{
  defwFunc = DEFW_SCANCHAIN;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (!inst || !*inst) {  // require
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + START %s", inst);
  if (pin) {
    fprintf(defwFile, " %s", pin);
  }
  defwLines++;

  defwState = DEFW_SCANCHAIN;
  return DEFW_OK;
}

int defwScanchainStop(const char* inst, const char* pin)
{
  defwFunc = DEFW_SCANCHAIN;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (!inst || !*inst) {  // require
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "\n      + STOP %s", inst);
  if (pin) {
    fprintf(defwFile, " %s", pin);
  }
  defwLines++;

  defwState = DEFW_SCANCHAIN;
  return DEFW_OK;
}

int defwScanchainFloating(const char* name,
                          const char* inst1,
                          const char* pin1,
                          const char* inst2,
                          const char* pin2)
{
  defwFunc = DEFW_SCAN_FLOATING;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (!name || !*name) {  // require
    return DEFW_BAD_DATA;
  }
  if (inst1 && strcmp(inst1, "IN") && strcmp(inst1, "OUT")) {
    return DEFW_BAD_DATA;
  }
  if (inst2 && strcmp(inst2, "IN") && strcmp(inst2, "OUT")) {
    return DEFW_BAD_DATA;
  }
  if (inst1 && !pin1) {
    return DEFW_BAD_DATA;
  }
  if (inst2 && !pin2) {
    return DEFW_BAD_DATA;
  }

  if (defwState != DEFW_SCAN_FLOATING) {
    fprintf(defwFile, "\n      + FLOATING");
  } else {
    fprintf(defwFile, "\n         ");
  }

  fprintf(defwFile, " %s", name);
  if (inst1) {
    fprintf(defwFile, " ( %s %s )", inst1, pin1);
  }
  if (inst2) {
    fprintf(defwFile, " ( %s %s )", inst2, pin2);
  }

  defwState = DEFW_SCAN_FLOATING;
  defwLines++;

  return DEFW_OK;
}

int defwScanchainFloatingBits(const char* name,
                              const char* inst1,
                              const char* pin1,
                              const char* inst2,
                              const char* pin2,
                              int bits)
{
  defwFunc = DEFW_SCAN_FLOATING;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (!name || !*name) {  // require
    return DEFW_BAD_DATA;
  }
  if (inst1 && strcmp(inst1, "IN") && strcmp(inst1, "OUT")) {
    return DEFW_BAD_DATA;
  }
  if (inst2 && strcmp(inst2, "IN") && strcmp(inst2, "OUT")) {
    return DEFW_BAD_DATA;
  }
  if (inst1 && !pin1) {
    return DEFW_BAD_DATA;
  }
  if (inst2 && !pin2) {
    return DEFW_BAD_DATA;
  }

  if (defwState != DEFW_SCAN_FLOATING) {
    fprintf(defwFile, "\n      + FLOATING");
  } else {
    fprintf(defwFile, "\n         ");
  }

  fprintf(defwFile, " %s", name);
  if (inst1) {
    fprintf(defwFile, " ( %s %s )", inst1, pin1);
  }
  if (inst2) {
    fprintf(defwFile, " ( %s %s )", inst2, pin2);
  }
  if (bits != -1) {
    fprintf(defwFile, " ( BITS %d )", bits);
  }

  defwState = DEFW_SCAN_FLOATING;
  defwLines++;

  return DEFW_OK;
}
int defwScanchainOrdered(const char* name1,
                         const char* inst1,
                         const char* pin1,
                         const char* inst2,
                         const char* pin2,
                         const char* name2,
                         const char* inst3,
                         const char* pin3,
                         const char* inst4,
                         const char* pin4)
{
  defwFunc = DEFW_SCAN_ORDERED;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (!name1 || !*name1) {  // require
    return DEFW_BAD_DATA;
  }
  if (inst1 && strcmp(inst1, "IN") && strcmp(inst1, "OUT")) {
    return DEFW_BAD_DATA;
  }
  if (inst2 && strcmp(inst2, "IN") && strcmp(inst2, "OUT")) {
    return DEFW_BAD_DATA;
  }
  if (inst1 && !pin1) {
    return DEFW_BAD_DATA;
  }
  if (inst2 && !pin2) {
    return DEFW_BAD_DATA;
  }
  if (defwState != DEFW_SCAN_ORDERED) {  // 1st time require both name1 & name2
    if (!name2 || !*name2) {             // require
      return DEFW_BAD_DATA;
    }
    if (inst3 && strcmp(inst3, "IN") && strcmp(inst3, "OUT")) {
      return DEFW_BAD_DATA;
    }
    if (inst4 && strcmp(inst4, "IN") && strcmp(inst4, "OUT")) {
      return DEFW_BAD_DATA;
    }
    if (inst3 && !pin3) {
      return DEFW_BAD_DATA;
    }
    if (inst4 && !pin4) {
      return DEFW_BAD_DATA;
    }
  }

  if (defwState != DEFW_SCAN_ORDERED) {
    fprintf(defwFile, "\n      + ORDERED");
  } else {
    fprintf(defwFile, "\n         ");
  }

  fprintf(defwFile, " %s", name1);
  if (inst1) {
    fprintf(defwFile, " ( %s %s )", inst1, pin1);
  }
  if (inst2) {
    fprintf(defwFile, " ( %s %s )", inst2, pin2);
  }
  defwLines++;

  if (name2) {
    fprintf(defwFile, "\n          %s", name2);
    if (inst3) {
      fprintf(defwFile, " ( %s %s )", inst3, pin3);
    }
    if (inst4) {
      fprintf(defwFile, " ( %s %s )", inst4, pin4);
    }
    defwLines++;
  }

  defwState = DEFW_SCAN_ORDERED;

  return DEFW_OK;
}

int defwScanchainOrderedBits(const char* name1,
                             const char* inst1,
                             const char* pin1,
                             const char* inst2,
                             const char* pin2,
                             int bits1,
                             const char* name2,
                             const char* inst3,
                             const char* pin3,
                             const char* inst4,
                             const char* pin4,
                             int bits2)
{
  defwFunc = DEFW_SCAN_ORDERED;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCANCHAIN
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCAN_ORDERED) {
    return DEFW_BAD_ORDER;
  }

  if (!name1 || !*name1) {  // require
    return DEFW_BAD_DATA;
  }
  if (inst1 && strcmp(inst1, "IN") && strcmp(inst1, "OUT")) {
    return DEFW_BAD_DATA;
  }
  if (inst2 && strcmp(inst2, "IN") && strcmp(inst2, "OUT")) {
    return DEFW_BAD_DATA;
  }
  if (inst1 && !pin1) {
    return DEFW_BAD_DATA;
  }
  if (inst2 && !pin2) {
    return DEFW_BAD_DATA;
  }
  if (defwState != DEFW_SCAN_ORDERED) {  // 1st time require both name1 & name2
    if (!name2 || !*name2) {             // require
      return DEFW_BAD_DATA;
    }
    if (inst3 && strcmp(inst3, "IN") && strcmp(inst3, "OUT")) {
      return DEFW_BAD_DATA;
    }
    if (inst4 && strcmp(inst4, "IN") && strcmp(inst4, "OUT")) {
      return DEFW_BAD_DATA;
    }
    if (inst3 && !pin3) {
      return DEFW_BAD_DATA;
    }
    if (inst4 && !pin4) {
      return DEFW_BAD_DATA;
    }
  }

  if (defwState != DEFW_SCAN_ORDERED) {
    fprintf(defwFile, "\n      + ORDERED");
  } else {
    fprintf(defwFile, "\n         ");
  }

  fprintf(defwFile, " %s", name1);
  if (inst1) {
    fprintf(defwFile, " ( %s %s )", inst1, pin1);
  }
  if (inst2) {
    fprintf(defwFile, " ( %s %s )", inst2, pin2);
  }
  if (bits1 != -1) {
    fprintf(defwFile, " ( BITS %d )", bits1);
  }
  defwLines++;

  if (name2) {
    fprintf(defwFile, "\n          %s", name2);
    if (inst3) {
      fprintf(defwFile, " ( %s %s )", inst3, pin3);
    }
    if (inst4) {
      fprintf(defwFile, " ( %s %s )", inst4, pin4);
    }
    if (bits2 != -1) {
      fprintf(defwFile, " ( BITS %d )", bits2);
    }
    defwLines++;
  }

  defwState = DEFW_SCAN_ORDERED;

  return DEFW_OK;
}

int defwEndScanchain()
{
  defwFunc = DEFW_SCANCHAIN_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SCANCHAIN_START && defwState != DEFW_SCAN_ORDERED
      && defwState != DEFW_SCAN_FLOATING && defwState != DEFW_SCANCHAIN) {
    return DEFW_BAD_ORDER;
  }

  if (defwState != DEFW_SCANCHAIN_START) {  // from previous statement
    fprintf(defwFile, " ;\n");
  }

  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, "END SCANCHAINS\n\n");
  defwLines++;

  defwState = DEFW_SCANCHAIN_END;
  return DEFW_OK;
}

int defwStartConstraints(int count)
{
  defwObsoleteNum = DEFW_FPC_START;
  defwFunc = DEFW_FPC_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_FPC_START) && (defwState <= DEFW_FPC_END)) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum >= 5.4) {
    return DEFW_OBSOLETE;
  }

  fprintf(defwFile, "CONSTRAINTS %d ;\n", count);
  defwLines++;

  defwState = DEFW_FPC_START;
  defwCounter = count;
  return DEFW_OK;
}

int defwConstraintOperand()
{
  defwFunc = DEFW_FPC_OPER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_START && defwState != DEFW_FPC) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "   -");
  defwCounter--;
  defwFPC = 0;
  defwState = DEFW_FPC_OPER;
  return DEFW_OK;
}

int defwConstraintOperandNet(const char* netName)
{
  defwFunc = DEFW_FPC_OPER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_OPER && defwState != DEFW_FPC_OPER_SUM) {
    return DEFW_BAD_ORDER;  // net can be within SUM
  }

  if (!netName || !*netName) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwFPC > 0) {
    fprintf(defwFile, " ,");
  }
  if (defwState == DEFW_FPC_OPER_SUM) {
    defwFPC++;
  }
  fprintf(defwFile, " NET %s", netName);
  return DEFW_OK;
}

int defwConstraintOperandPath(const char* comp1,
                              const char* fromPin,
                              const char* comp2,
                              const char* toPin)
{
  defwFunc = DEFW_FPC_OPER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_OPER && defwState != DEFW_FPC_OPER_SUM) {
    return DEFW_BAD_ORDER;  // path can be within SUM
  }

  if ((comp1 == nullptr) || (*comp1 == 0) || (fromPin == nullptr)
      || (*fromPin == 0) || (comp2 == nullptr) || (*comp2 == 0)
      || (toPin == nullptr) || (*toPin == 0)) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwFPC > 0) {
    fprintf(defwFile, " ,");
  }
  if (defwState == DEFW_FPC_OPER_SUM) {
    defwFPC++;
  }
  fprintf(defwFile, " PATH %s %s %s %s", comp1, fromPin, comp2, toPin);
  return DEFW_OK;
}

int defwConstraintOperandSum()
{
  defwFunc = DEFW_FPC_OPER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_OPER && defwState != DEFW_FPC_OPER_SUM) {
    return DEFW_BAD_ORDER;  // sum can be within SUM
  }

  fprintf(defwFile, " SUM (");
  defwState = DEFW_FPC_OPER_SUM;
  defwFPC = 0;
  return DEFW_OK;
}

int defwConstraintOperandSumEnd()
{
  defwFunc = DEFW_FPC_OPER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_OPER_SUM) {
    return DEFW_BAD_ORDER;
  }
  fprintf(defwFile, " )");
  defwState = DEFW_FPC_OPER;
  defwFPC = 0;
  return DEFW_OK;
}

int defwConstraintOperandTime(const char* timeType, int time)
{
  defwFunc = DEFW_FPC_OPER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_OPER) {
    return DEFW_BAD_ORDER;
  }
  if (timeType && strcmp(timeType, "RISEMAX") && strcmp(timeType, "FALLMAX")
      && strcmp(timeType, "RISEMIN") && strcmp(timeType, "FALLMIN")) {
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, " + %s %d", timeType, time);
  return DEFW_OK;
}

int defwConstraintOperandEnd()
{
  defwFunc = DEFW_FPC_OPER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_OPER) {
    return DEFW_BAD_ORDER;
  }
  fprintf(defwFile, " ;\n");
  defwState = DEFW_FPC;
  return DEFW_OK;
}

int defwConstraintWiredlogic(const char* netName, int distance)
{
  defwFunc = DEFW_FPC;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_START && defwState != DEFW_FPC) {
    return DEFW_BAD_ORDER;
  }

  if (!netName || !*netName) {  // require
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "   - WIREDLOGIC %s MAXDIST %d ;\n", netName, distance);
  defwCounter--;
  defwState = DEFW_FPC;
  defwLines++;
  return DEFW_OK;
}

int defwEndConstraints()
{
  defwFunc = DEFW_FPC_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FPC_START && defwState != DEFW_FPC) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, "END CONSTRAINTS\n\n");
  defwLines++;

  defwState = DEFW_FPC_END;
  return DEFW_OK;
}

int defwStartGroups(int count)
{
  defwFunc = DEFW_GROUP_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_GROUP_START) && (defwState <= DEFW_GROUP_END)) {
    return DEFW_BAD_ORDER;
  }

  fprintf(defwFile, "GROUPS %d ;\n", count);
  defwLines++;

  defwState = DEFW_GROUP_START;
  defwCounter = count;
  return DEFW_OK;
}

int defwGroup(const char* groupName, int numExpr, const char** groupExpr)
{
  int i;

  defwFunc = DEFW_GROUP;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_GROUP_START && defwState != DEFW_GROUP) {
    return DEFW_BAD_ORDER;
  }

  if ((groupName == nullptr) || (*groupName == 0) || (groupExpr == nullptr)
      || (*groupExpr == nullptr)) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_GROUP) {
    fprintf(defwFile, " ;\n");  // add ; for the previous group
  }
  fprintf(defwFile, "   - %s", groupName);
  if (numExpr) {
    for (i = 0; i < numExpr; i++) {
      fprintf(defwFile, " %s", groupExpr[i]);
    }
  }
  defwCounter--;
  defwLines++;
  defwState = DEFW_GROUP;
  return DEFW_OK;
}

int defwGroupSoft(const char* type1,
                  double value1,
                  const char* type2,
                  double value2,
                  const char* type3,
                  double value3)
{
  defwFunc = DEFW_GROUP;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_GROUP) {
    return DEFW_BAD_ORDER;
  }

  if (type1 && strcmp(type1, "MAXHALFPERIMETER") && strcmp(type1, "MAXX")
      && strcmp(type1, "MAXY")) {
    return DEFW_BAD_DATA;
  }
  if (type2 && strcmp(type2, "MAXHALFPERIMETER") && strcmp(type2, "MAXX")
      && strcmp(type2, "MAXY")) {
    return DEFW_BAD_DATA;
  }
  if (type3 && strcmp(type3, "MAXHALFPERIMETER") && strcmp(type3, "MAXX")
      && strcmp(type3, "MAXY")) {
    return DEFW_BAD_DATA;
  }
  if (type1) {
    fprintf(defwFile, "\n     + SOFT %s %.11g", type1, value1);
  }
  if (type2) {
    fprintf(defwFile, " %s %.11g", type2, value2);
  }
  if (type3) {
    fprintf(defwFile, " %s %.11g", type3, value3);
  }
  defwLines++;
  return DEFW_OK;
}

int defwGroupRegion(int xl, int yl, int xh, int yh, const char* regionName)
{
  defwFunc = DEFW_GROUP;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_GROUP) {
    return DEFW_BAD_ORDER;
  }

  if ((xl || yl || xh || yh) && (regionName)) {  // ether pts or regionName
    return DEFW_BAD_DATA;
  }

  if (regionName) {
    fprintf(defwFile, "\n      + REGION %s", regionName);
  } else {
    fprintf(defwFile, "\n      + REGION ( %d %d ) ( %d %d )", xl, yl, xh, yh);
  }
  defwLines++;
  return DEFW_OK;
}

int defwEndGroups()
{
  defwFunc = DEFW_GROUP_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_GROUP_START && defwState != DEFW_GROUP) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  if (defwState != DEFW_GROUP_START) {
    fprintf(defwFile, " ;\n");
  }

  fprintf(defwFile, "END GROUPS\n\n");
  defwLines++;

  defwState = DEFW_GROUP_END;
  return DEFW_OK;
}

int defwStartBlockages(int count)
{
  defwFunc = DEFW_BLOCKAGE_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_BLOCKAGE_START) && (defwState <= DEFW_BLOCKAGE_END)) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "BLOCKAGES %d ;\n", count);
  defwLines++;

  defwState = DEFW_BLOCKAGE_START;
  defwCounter = count;
  return DEFW_OK;
}

int defwBlockagesLayer(const char* layerName)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_PLACE)
          || (defwState == DEFW_BLOCKAGE_LAYER))) {
    return DEFW_BAD_ORDER;
  }

  if (!layerName || !*layerName) {  // require
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }

  fprintf(defwFile, "   - LAYER %s", layerName);
  fprintf(defwFile, "\n");
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  defwBlockageHasSD = 0;
  defwBlockageHasSF = 0;
  return DEFW_OK;
}

int defwBlockagesLayerSlots()
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if (defwBlockageHasSF) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "      + SLOTS\n");
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  defwBlockageHasSF = 1;
  return DEFW_OK;
}

int defwBlockagesLayerFills()
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if (defwBlockageHasSF) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }

  fprintf(defwFile, "     + FILLS\n");
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  defwBlockageHasSF = 1;
  return DEFW_OK;
}

int defwBlockagesLayerComponent(const char* compName)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if ((compName == nullptr) || (*compName == 0)) {  // require
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "     + COMPONENT %s\n", compName);
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

int defwBlockagesLayerPushdown()
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }

  fprintf(defwFile, "     + PUSHDOWN\n");
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

// 5.7
int defwBlockagesLayerExceptpgnet()
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }

  fprintf(defwFile, "     + EXCEPTPGNET\n");
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

int defwBlockagesLayerSpacing(int minSpacing)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }
  if (defwBlockageHasSD) {  // Either spacing or designrulewidth has defined
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "     + SPACING %d\n", minSpacing);
  defwLines++;
  defwBlockageHasSD = 1;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

int defwBlockagesLayerDesignRuleWidth(int effectiveWidth)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }
  if (defwBlockageHasSD) {  // Either spacing or designrulewidth has defined
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "     + DESIGNRULEWIDTH %d\n", effectiveWidth);
  defwLines++;
  defwBlockageHasSD = 1;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

int defwBlockagesLayerMask(int colorMask)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_BLOCKAGE_MASK;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     + MASK %d", colorMask);
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

// To be removed, replaced by defwBlockagesLayer
int defwBlockageLayer(const char* layerName, const char* compName)
{                                  // optional(NULL)
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define component or layer slots or fills
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_PLACE)
          || (defwState == DEFW_BLOCKAGE_LAYER))) {
    return DEFW_BAD_DATA;
  }

  if (!layerName || !*layerName) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - LAYER %s ", layerName);
  if (compName && *compName != 0) {  // optional
    fprintf(defwFile, "+ COMPONENT %s ", compName);
  }
  fprintf(defwFile, "\n");
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  defwBlockageHasSD = 0;
  return DEFW_OK;
}

// To be removed, replaced by defwBlockagesLayerSlots
int defwBlockageLayerSlots(const char* layerName)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define component or layer or layer fills
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_PLACE)
          || (defwState == DEFW_BLOCKAGE_LAYER))) {
    return DEFW_BAD_DATA;
  }

  if (!layerName || !*layerName) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - LAYER %s + SLOTS\n", layerName);
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  defwBlockageHasSD = 0;
  return DEFW_OK;
}

// To be removed, replaced by defwBlockagesLayerFills
int defwBlockageLayerFills(const char* layerName)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define component or layer or layer slots
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_PLACE)
          || (defwState == DEFW_BLOCKAGE_LAYER))) {
    return DEFW_BAD_DATA;
  }

  if (!layerName || !*layerName) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - LAYER %s + FILLS\n", layerName);
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  defwBlockageHasSD = 0;
  return DEFW_OK;
}

// To be removed, replaced by defwBlockagesLayerPushdown
int defwBlockageLayerPushdown(const char* layerName)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define component or layer or layer slots
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_PLACE)
          || (defwState == DEFW_BLOCKAGE_LAYER))) {
    return DEFW_BAD_DATA;
  }

  if ((layerName == nullptr) || (*layerName == 0)) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - LAYER %s + PUSHDOWN\n", layerName);
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  defwBlockageHasSD = 0;
  return DEFW_OK;
}

// To be removed, replaced by defwBlockagesLayerExceptpgnet
int defwBlockageLayerExceptpgnet(const char* layerName)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define component or layer or layer slots
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_PLACE)
          || (defwState == DEFW_BLOCKAGE_LAYER))) {
    return DEFW_BAD_DATA;
  }

  if ((layerName == nullptr) || (*layerName == 0)) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - LAYER %s + EXCEPTPGNET\n", layerName);
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  defwBlockageHasSD = 0;
  return DEFW_OK;
}

// To be removed, replaced by defwBlockagesLayerSpacing
int defwBlockageSpacing(int minSpacing)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // Checked if defwBlockageDesignRuleWidth has already called
  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_DATA;
  }
  if (defwBlockageHasSD) {  // Either spacing or designrulewidth has defined
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "     + SPACING %d\n", minSpacing);
  defwLines++;
  defwBlockageHasSD = 1;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

// To be removed, replaced by defwBlockagesLayerDesignRuleWidth
int defwBlockageDesignRuleWidth(int effectiveWidth)
{
  defwFunc = DEFW_BLOCKAGE_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // Checked if defwBlockageDesignRuleWidth has already called
  if ((defwState != DEFW_BLOCKAGE_LAYER) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_DATA;
  }
  if (defwBlockageHasSD) {  // Either spacing or designrulewidth has defined
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "     + DESIGNRULEWIDTH %d\n", effectiveWidth);
  defwLines++;
  defwBlockageHasSD = 1;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

int defwBlockagesPlacement()
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_LAYER)
          || (defwState == DEFW_BLOCKAGE_PLACE))) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }

  fprintf(defwFile, "   - PLACEMENT\n");
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  defwBlockageHasSP = 0;
  return DEFW_OK;
}

int defwBlockagesPlacementComponent(const char* compName)
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_PLACE) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if ((compName == nullptr) || (*compName == 0)) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "     + COMPONENT %s\n", compName);
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  return DEFW_OK;
}

int defwBlockagesPlacementPushdown()
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_PLACE) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "     + PUSHDOWN\n");
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  return DEFW_OK;
}

// 5.7
int defwBlockagesPlacementSoft()
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_PLACE) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if (defwBlockageHasSP) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "     + SOFT\n");
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  defwBlockageHasSP = 1;
  return DEFW_OK;
}

// 5.7
int defwBlockagesPlacementPartial(double maxDensity)
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }

  if ((defwState != DEFW_BLOCKAGE_PLACE) && (defwState != DEFW_BLOCKAGE_RECT)) {
    return DEFW_BAD_ORDER;
  }

  if (defwBlockageHasSP) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "     + PARTIAL %.11g\n", maxDensity);
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  defwBlockageHasSP = 1;
  return DEFW_OK;
}

int defwBlockagesRect(int xl, int yl, int xh, int yh)
{
  defwFunc = DEFW_BLOCKAGE_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_PLACE && defwState != DEFW_BLOCKAGE_LAYER
      && defwState != DEFW_BLOCKAGE_RECT) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     RECT ( %d %d ) ( %d %d )", xl, yl, xh, yh);
  defwLines++;
  defwState = DEFW_BLOCKAGE_RECT;
  return DEFW_OK;
}

int defwBlockagesPolygon(int num_polys, int* xl, int* yl)
{
  int i;

  defwFunc = DEFW_BLOCKAGE_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_LAYER && defwState != DEFW_BLOCKAGE_RECT) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     POLYGON ");
  for (i = 0; i < num_polys; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      fprintf(defwFile, "( %d %d ) ", *xl++, *yl++);
    } else {
      fprintf(defwFile, "\n             ( %d %d ) ", *xl++, *yl++);
      defwLines++;
    }
  }
  defwLines++;
  defwState = DEFW_BLOCKAGE_RECT;  // use rect flag.  It works the same for poly
  return DEFW_OK;
}

// To be removed. Will replace by defwBlcokagesPlacement
// bug fix: submitted by Craig Files (cfiles@ftc.agilent.com)
int defwBlockagePlacement()
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_LAYER)
          || (defwState == DEFW_BLOCKAGE_PLACE))) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - PLACEMENT\n");
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  return DEFW_OK;
}

// To be removed. Will replace by defwBlcokagesPlacementComponent
int defwBlockagePlacementComponent(const char* compName)
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_LAYER)
          || (defwState == DEFW_BLOCKAGE_PLACE))) {
    return DEFW_BAD_DATA;
  }

  if ((compName == nullptr) || (*compName == 0)) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - PLACEMENT + COMPONENT %s\n", compName);
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  return DEFW_OK;
}

// To be removed. Will replace by defwBlcokagesPlacementPushdown
int defwBlockagePlacementPushdown()
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_LAYER)
          || (defwState == DEFW_BLOCKAGE_PLACE))) {
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - PLACEMENT + PUSHDOWN\n");
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  return DEFW_OK;
}

// To be removed. Will replace by defwBlcokagesPlacementSoft
int defwBlockagePlacementSoft()
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_LAYER)
          || (defwState == DEFW_BLOCKAGE_PLACE))) {
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - PLACEMENT + SOFT\n");
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  return DEFW_OK;
}

// To be removed. Will replace by defwBlcokagesPlacementPartial
int defwBlockagePlacementPartial(double maxDensity)
{
  defwFunc = DEFW_BLOCKAGE_PLACE;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_START
      && ((defwState == DEFW_BLOCKAGE_LAYER)
          || (defwState == DEFW_BLOCKAGE_PLACE))) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - PLACEMENT + PARTIAL %.11g\n", maxDensity);
  defwCounter--;
  defwLines++;
  defwState = DEFW_BLOCKAGE_PLACE;
  return DEFW_OK;
}

// To be removed. Will replace by defwBlockagesLayerMask
int defwBlockageMask(int colorMask)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_BLOCKAGE_MASK;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_PLACE && defwState != DEFW_BLOCKAGE_LAYER
      && defwState != DEFW_BLOCKAGE_RECT) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     + MASK %d", colorMask);
  defwLines++;
  defwState = DEFW_BLOCKAGE_LAYER;
  return DEFW_OK;
}

// Tobe removed. Will be replaced by defwBlockagesRect.
int defwBlockageRect(int xl, int yl, int xh, int yh)
{
  defwFunc = DEFW_BLOCKAGE_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_PLACE && defwState != DEFW_BLOCKAGE_LAYER
      && defwState != DEFW_BLOCKAGE_RECT && defwState != DEFW_BLOCKAGE_MASK) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     RECT ( %d %d ) ( %d %d )", xl, yl, xh, yh);
  defwLines++;
  defwState = DEFW_BLOCKAGE_RECT;
  return DEFW_OK;
}

// Tobe removed. Will be replaced by defwBlockagesPolygon.
int defwBlockagePolygon(int num_polys, int* xl, int* yl)
{
  int i;

  defwFunc = DEFW_BLOCKAGE_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_BLOCKAGE_LAYER && defwState != DEFW_BLOCKAGE_RECT
      && defwState != DEFW_BLOCKAGE_MASK) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_BLOCKAGE_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     POLYGON ");
  for (i = 0; i < num_polys; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      fprintf(defwFile, "( %d %d ) ", *xl++, *yl++);
    } else {
      fprintf(defwFile, "\n             ( %d %d ) ", *xl++, *yl++);
      defwLines++;
    }
  }
  defwLines++;
  defwState = DEFW_BLOCKAGE_RECT;  // use rect flag.  It works the same for poly
  return DEFW_OK;
}

int defwEndBlockages()
{
  defwFunc = DEFW_BLOCKAGE_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_BLOCKAGE_RECT) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, " ;\n");

  fprintf(defwFile, "END BLOCKAGES\n\n");
  defwLines++;

  defwState = DEFW_BLOCKAGE_END;
  return DEFW_OK;
}

int defwStartSlots(int count)
{
  defwFunc = DEFW_SLOT_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_SLOT_START) && (defwState <= DEFW_SLOT_END)) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "SLOTS %d ;\n", count);
  defwLines++;

  defwState = DEFW_SLOT_START;
  defwCounter = count;
  return DEFW_OK;
}

int defwSlotLayer(const char* layerName)
{
  defwFunc = DEFW_SLOT_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_SLOT_START && defwState == DEFW_SLOT_LAYER) {
    return DEFW_BAD_DATA;
  }

  if (!layerName || !*layerName) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_SLOT_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - LAYER %s \n", layerName);
  defwCounter--;
  defwLines++;
  defwState = DEFW_SLOT_LAYER;
  return DEFW_OK;
}

int defwSlotRect(int xl, int yl, int xh, int yh)
{
  defwFunc = DEFW_SLOT_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_SLOT_LAYER && defwState != DEFW_SLOT_RECT) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_SLOT_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     RECT ( %d %d ) ( %d %d )", xl, yl, xh, yh);
  defwLines++;
  defwState = DEFW_SLOT_RECT;
  return DEFW_OK;
}

int defwSlotPolygon(int num_polys, double* xl, double* yl)
{
  int i;

  defwFunc = DEFW_SLOT_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_SLOT_LAYER && defwState != DEFW_SLOT_RECT) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_SLOT_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     POLYGON ");

  printPointsNum = 0;
  for (i = 0; i < num_polys; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      printPoints(defwFile, *xl++, *yl++, "", " ");
    } else {
      printPoints(defwFile, *xl++, *yl++, "\n             ", " ");
      defwLines++;
    }
  }
  defwLines++;
  defwState = DEFW_SLOT_RECT;
  return DEFW_OK;
}

int defwEndSlots()
{
  defwFunc = DEFW_SLOT_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_SLOT_RECT) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, " ;\n");

  fprintf(defwFile, "END SLOTS\n\n");
  defwLines++;

  defwState = DEFW_SLOT_END;
  return DEFW_OK;
}

int defwStartFills(int count)
{
  defwFunc = DEFW_FILL_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_FILL_START) && (defwState <= DEFW_FILL_END)) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.4) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "FILLS %d ;\n", count);
  defwLines++;

  defwState = DEFW_FILL_START;
  defwCounter = count;
  return DEFW_OK;
}

int defwFillLayer(const char* layerName)
{
  defwFunc = DEFW_FILL_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_START && defwState == DEFW_FILL_LAYER) {
    return DEFW_BAD_DATA;
  }

  if (!layerName || !*layerName) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_FILL_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - LAYER %s \n", layerName);
  defwCounter--;
  defwLines++;
  defwState = DEFW_FILL_LAYER;
  return DEFW_OK;
}

int defwFillLayerMask(int colorMask)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_FILL_LAYERMASK;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_LAYER) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "     + MASK %d", colorMask);
  defwLines++;
  defwState = DEFW_FILL_LAYERMASK;
  return DEFW_OK;
}

// 5.71
int defwFillLayerOPC()
{
  defwFunc = DEFW_FILL_OPC;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_LAYER && defwState != DEFW_FILL_LAYERMASK) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "     + OPC");
  defwLines++;
  defwState = DEFW_FILL_OPC;
  return DEFW_OK;
}

int defwFillRect(int xl, int yl, int xh, int yh)
{
  defwFunc = DEFW_FILL_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_LAYER && defwState != DEFW_FILL_RECT
      && defwState != DEFW_FILL_OPC && defwState != DEFW_FILL_LAYERMASK) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_FILL_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     RECT ( %d %d ) ( %d %d )", xl, yl, xh, yh);
  defwLines++;
  defwState = DEFW_FILL_RECT;
  return DEFW_OK;
}

int defwFillPolygon(int num_polys, double* xl, double* yl)
{
  int i;

  defwFunc = DEFW_FILL_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_LAYER && defwState != DEFW_FILL_RECT
      && defwState != DEFW_FILL_OPC && defwState != DEFW_FILL_LAYERMASK) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_FILL_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     POLYGON ");
  printPointsNum = 0;
  for (i = 0; i < num_polys; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      printPoints(defwFile, *xl++, *yl++, "", " ");
    } else {
      printPoints(defwFile, *xl++, *yl++, "\n             ", " ");
      defwLines++;
    }
  }
  defwLines++;
  defwState = DEFW_FILL_RECT;
  return DEFW_OK;
}

// 5.7
int defwFillVia(const char* viaName)
{
  defwFunc = DEFW_FILL_LAYER;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_START && defwState == DEFW_FILL_LAYER) {
    return DEFW_BAD_DATA;
  }

  if (!viaName || !*viaName) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_FILL_RECT) {
    fprintf(defwFile, " ;\n");  // end the previous rectangle
  }
  fprintf(defwFile, "   - VIA %s \n", viaName);
  defwCounter--;
  defwLines++;
  defwState = DEFW_FILL_VIA;
  return DEFW_OK;
}

int defwFillViaMask(int maskColor)
{
  if (defVersionNum < 5.8) {
    return DEFW_WRONG_VERSION;
  }

  defwFunc = DEFW_FILL_VIAMASK;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_VIA) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "     + MASK %d", maskColor);
  defwLines++;
  defwState = DEFW_FILL_VIAMASK;
  return DEFW_OK;
}

// 5.71
int defwFillViaOPC()
{
  defwFunc = DEFW_FILL_OPC;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_VIA && defwState != DEFW_FILL_VIAMASK) {
    return DEFW_BAD_DATA;
  }

  fprintf(defwFile, "     + OPC");
  defwLines++;
  defwState = DEFW_FILL_OPC;
  return DEFW_OK;
}

int defwFillPoints(int num_points, double* xl, double* yl)
{
  int i;

  defwFunc = DEFW_FILL_RECT;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_FILL_VIA && defwState != DEFW_FILL_RECT
      && defwState != DEFW_FILL_OPC && defwState != DEFW_FILL_VIAMASK) {
    return DEFW_BAD_DATA;
  }

  if (defwState == DEFW_FILL_RECT) {
    fprintf(defwFile, "\n");  // set a newline for the previous rectangle
  }

  fprintf(defwFile, "     ");
  printPointsNum = 0;

  for (i = 0; i < num_points; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      printPoints(defwFile, *xl++, *yl++, "", " ");
    } else {
      printPoints(defwFile, *xl++, *yl++, "\n             ", " ");
      defwLines++;
    }
  }

  defwLines++;
  defwState = DEFW_FILL_RECT;
  return DEFW_OK;
}

int defwEndFills()
{
  defwFunc = DEFW_FILL_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_FILL_RECT && defwState != DEFW_FILL_OPC) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, " ;\n");

  fprintf(defwFile, "END FILLS\n\n");
  defwLines++;

  defwState = DEFW_FILL_END;
  return DEFW_OK;
}

int defwStartNonDefaultRules(int count)
{
  defwFunc = DEFW_NDR_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_NDR_START) && (defwState <= DEFW_NDR_END)) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "NONDEFAULTRULES %d ;\n", count);
  defwLines++;

  defwState = DEFW_NDR_START;
  defwCounter = count;
  return DEFW_OK;
}

int defwNonDefaultRule(const char* ruleName, int hardSpacing)
{
  defwFunc = DEFW_NDR;
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_NDR_START && defwState != DEFW_NDR) {
    return DEFW_BAD_ORDER;
  }

  if (!ruleName || !*ruleName) {  // require
    return DEFW_BAD_DATA;
  }
  if (defwState == DEFW_NDR) {
    fprintf(defwFile, ";\n");
  }
  fprintf(defwFile, "   - %s", ruleName);
  if (hardSpacing) {
    fprintf(defwFile, "\n      + HARDSPACING");
  }
  defwCounter--;
  defwLines++;
  defwState = DEFW_NDR;
  return DEFW_OK;
}

int defwNonDefaultRuleLayer(const char* layerName,
                            int width,
                            int diagWidth,
                            int spacing,
                            int wireExt)
{
  defwFunc = DEFW_NDR;
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_NDR) {
    return DEFW_BAD_ORDER;
  }

  if (!layerName || !*layerName) {  // require
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "\n      + LAYER %s ", layerName);
  fprintf(defwFile, " WIDTH %d ", width);
  if (diagWidth) {
    fprintf(defwFile, " DIAGWIDTH %d ", diagWidth);
  }
  if (spacing) {
    fprintf(defwFile, " SPACING %d ", spacing);
  }
  if (wireExt) {
    fprintf(defwFile, " WIREEXT %d ", wireExt);
  }
  defwLines++;
  defwState = DEFW_NDR;
  return DEFW_OK;
}

int defwNonDefaultRuleVia(const char* viaName)
{
  defwFunc = DEFW_NDR;
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_NDR) {
    return DEFW_BAD_ORDER;
  }

  if (!viaName || !*viaName) {  // require
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "\n      + VIA %s ", viaName);
  defwLines++;
  defwState = DEFW_NDR;
  return DEFW_OK;
}

int defwNonDefaultRuleViaRule(const char* viaRuleName)
{
  defwFunc = DEFW_NDR;
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_NDR) {
    return DEFW_BAD_ORDER;
  }

  if ((viaRuleName == nullptr) || (*viaRuleName == 0)) {  // require
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "\n      + VIARULE %s ", viaRuleName);
  defwLines++;
  defwState = DEFW_NDR;
  return DEFW_OK;
}

int defwNonDefaultRuleMinCuts(const char* cutLayerName, int numCuts)
{
  defwFunc = DEFW_NDR;
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_NDR) {
    return DEFW_BAD_ORDER;
  }

  if ((cutLayerName == nullptr) || (*cutLayerName == 0)) {  // require
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "\n      + MINCUTS %s %d ", cutLayerName, numCuts);
  defwLines++;
  defwState = DEFW_NDR;
  return DEFW_OK;
}

int defwEndNonDefaultRules()
{
  defwFunc = DEFW_NDR_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_NDR) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, ";\nEND NONDEFAULTRULES\n\n");
  defwLines++;

  defwState = DEFW_NDR_END;
  return DEFW_OK;
}

int defwStartStyles(int count)
{
  defwFunc = DEFW_STYLES_START;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if ((defwState >= DEFW_STYLES_START) && (defwState <= DEFW_STYLES_END)) {
    return DEFW_BAD_ORDER;
  }
  if (defVersionNum < 5.6) {
    return DEFW_WRONG_VERSION;
  }

  fprintf(defwFile, "STYLES %d ;\n", count);
  defwLines++;

  defwState = DEFW_STYLES_START;
  defwCounter = count;
  return DEFW_OK;
}

int defwStyles(int styleNums, int num_points, double* xp, double* yp)
{
  int i;

  defwFunc = DEFW_STYLES;
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  // May be user already define layer
  if (defwState != DEFW_STYLES_START && defwState != DEFW_STYLES) {
    return DEFW_BAD_ORDER;
  }

  if (styleNums < 0) {  // require
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "   - STYLE %d ", styleNums);

  printPointsNum = 0;
  for (i = 0; i < num_points; i++) {
    if ((i == 0) || ((i % 5) != 0)) {
      printPoints(defwFile, *xp++, *yp++, "", " ");
    } else {
      printPoints(defwFile, *xp++, *yp++, "\n       ", " ");
      defwLines++;
    }
  }

  defwCounter--;
  defwLines++;
  fprintf(defwFile, ";\n");
  defwState = DEFW_STYLES;
  return DEFW_OK;
}

int defwEndStyles()
{
  defwFunc = DEFW_STYLES_END;  // Current function of writer
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (defwState != DEFW_STYLES) {
    return DEFW_BAD_ORDER;
  }
  if (defwCounter > 0) {
    return DEFW_BAD_DATA;
  }
  if (defwCounter < 0) {
    return DEFW_TOO_MANY_STMS;
  }

  fprintf(defwFile, "END STYLES\n\n");
  defwLines++;

  defwState = DEFW_STYLES_END;
  return DEFW_OK;
}

int defwStartBeginext(const char* name)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState == DEFW_BEGINEXT_START || defwState == DEFW_BEGINEXT) {
    return DEFW_BAD_ORDER;
  }
  if (!name || name == nullptr || *name == 0) {
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "BEGINEXT \"%s\"\n", name);

  defwState = DEFW_BEGINEXT_START;
  defwLines++;
  return DEFW_OK;
}

int defwBeginextCreator(const char* creatorName)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState != DEFW_BEGINEXT_START && defwState != DEFW_BEGINEXT) {
    return DEFW_BAD_ORDER;
  }
  if (!creatorName || creatorName == nullptr || *creatorName == 0) {
    return DEFW_BAD_DATA;
  }
  fprintf(defwFile, "   CREATOR \"%s\"\n", creatorName);

  defwState = DEFW_BEGINEXT;
  defwLines++;
  return DEFW_OK;
}

int defwBeginextDate()
{
  time_t todayTime;
  char* rettime;

  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState != DEFW_BEGINEXT_START && defwState != DEFW_BEGINEXT) {
    return DEFW_BAD_ORDER;
  }

  todayTime = time(nullptr);            // time in UTC
  rettime = ctime(&todayTime);          // convert to string
  rettime[strlen(rettime) - 1] = '\0';  // replace \n with \0
  fprintf(defwFile, "   DATE \"%s\"", rettime);

  defwState = DEFW_BEGINEXT;
  defwLines++;
  return DEFW_OK;
}

int defwBeginextRevision(int vers1, int vers2)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState != DEFW_BEGINEXT_START && defwState != DEFW_BEGINEXT) {
    return DEFW_BAD_ORDER;
  }
  fprintf(defwFile, "\n   REVISION %d.%d", vers1, vers2);

  defwState = DEFW_BEGINEXT;
  defwLines++;
  return DEFW_OK;
}

int defwBeginextSyntax(const char* title, const char* string)
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState != DEFW_BEGINEXT_START && defwState != DEFW_BEGINEXT) {
    return DEFW_BAD_ORDER;
  }
  fprintf(defwFile, "\n   - %s %s", title, string);

  defwState = DEFW_BEGINEXT;
  defwLines++;
  return DEFW_OK;
}

int defwEndBeginext()
{
  if (!defwFile) {
    return DEFW_UNINITIALIZED;
  }
  if (!defwDidInit) {
    return DEFW_BAD_ORDER;
  }
  if (defwState != DEFW_BEGINEXT_START && defwState != DEFW_BEGINEXT) {
    return DEFW_BAD_ORDER;
  }
  fprintf(defwFile, ";\nENDEXT\n\n");

  defwState = DEFW_BEGINEXT_END;
  defwLines++;
  return DEFW_OK;
}

int defwEnd()
{
  defwFunc = DEFW_END;  // Current function of writer
  if (!defwFile) {
    return 1;
  }

  if (defwState == DEFW_ROW) {
    fprintf(defwFile, ";\n\n");  // add the ; and \n for the previous row.
  }

  fprintf(defwFile, "END DESIGN\n\n");
  defwLines++;
  // defwFile = 0;
  defwState = DEFW_DONE;
  return DEFW_OK;
}

int defwCurrentLineNumber()
{
  return defwLines;
}

void defwPrintError(int status)
{
  switch (status) {
    case DEFW_OK:
      fprintf(defwFile, "No Error.\n");
      break;
    case DEFW_UNINITIALIZED:
      printf("Need to call defwInit first.\n");
      break;
    case DEFW_BAD_ORDER:
      fprintf(
          defwFile, "%s - Incorrect order of data.\n", defwStateStr[defwFunc]);
      break;
    case DEFW_BAD_DATA:
      fprintf(defwFile, "%s - Invalid data.\n", defwStateStr[defwFunc]);
      break;
    case DEFW_ALREADY_DEFINED:
      fprintf(defwFile,
              "%s - Section is allowed to define only once.\n",
              defwStateStr[defwFunc]);
      break;
    case DEFW_WRONG_VERSION:
      fprintf(defwFile,
              "%s - Version number is set before 5.6, but 5.6 API is used.\n",
              defwStateStr[defwFunc]);
      break;
    case DEFW_OBSOLETE:
      fprintf(defwFile,
              "%s - is no longer valid in 5.6.\n",
              defwStateStr[defwObsoleteNum]);
      break;
  }
  return;
}

void defwAddComment(const char* comment)
{
  if (comment) {
    fprintf(defwFile, "# %s\n", comment);
  }
  return;
}

void defwAddIndent()
{
  fprintf(defwFile, "   ");
  return;
}

//***************************
//   Questions:
// - Is only one row rule allowed
// - Is only one tracks rule allowed
// - In the die area is a zero area allowed? overlaps?
// - What type of checking is needed for the rows and tracks do loop?
// - Can you have a default prop with a number AND a range?
// - What is the pin properties section mentioned in the 5.1 spec?
// *****************************

END_DEF_PARSER_NAMESPACE
